Merge branch 'develop' into improvement/move-app-to-src-2

This commit is contained in:
Hypolite Petovan 2017-05-07 12:58:11 -04:00 committed by GitHub
commit 86cae070f2
21 changed files with 5720 additions and 5348 deletions

View File

@ -40,7 +40,7 @@ define ( 'FRIENDICA_PLATFORM', 'Friendica');
define ( 'FRIENDICA_CODENAME', 'Asparagus');
define ( 'FRIENDICA_VERSION', '3.5.2-dev' );
define ( 'DFRN_PROTOCOL_VERSION', '2.23' );
define ( 'DB_UPDATE_VERSION', 1222 );
define ( 'DB_UPDATE_VERSION', 1224 );
/**
* @brief Constant with a HTML line break.

View File

@ -172,6 +172,11 @@ On error:
HTTP 400 BadRequest
* on friendica_verbose=true: different JSON returns {"result":"error","message":"xyz"}
---
### externalprofile/show (*)
#### Parameters
* profileurl: profile url
---
### favorites (*; AUTH)
#### Parameters

View File

@ -175,6 +175,9 @@ class Probe {
return array();
$host = $parts["host"];
if (isset($parts["port"])) {
$host .= ':'.$parts["port"];
}
$path_parts = explode("/", trim($parts["path"], "/"));
@ -335,8 +338,10 @@ class Probe {
if (isset($parts["scheme"]) AND isset($parts["host"]) AND isset($parts["path"])) {
/// @todo: Ports?
$host = $parts["host"];
if (isset($parts["port"])) {
$host .= ':'.$parts["port"];
}
if ($host == 'twitter.com') {
return array("network" => NETWORK_TWITTER);
@ -789,7 +794,7 @@ class Probe {
if (sizeof($avatar)) {
ksort($avatar);
$data["photo"] = array_pop($avatar);
$data["photo"] = self::fix_avatar(array_pop($avatar), $data["baseurl"]);
}
if ($dfrn) {
@ -960,7 +965,7 @@ class Probe {
$data["nick"] = $feed_data["header"]["author-nick"];
}
if ($feed_data["header"]["author-avatar"] != "") {
$data["photo"] = ostatus::fix_avatar($feed_data["header"]["author-avatar"], $data["url"]);
$data["photo"] = self::fix_avatar($feed_data["header"]["author-avatar"], $data["url"]);
}
if ($feed_data["header"]["author-id"] != "") {
$data["alias"] = $feed_data["header"]["author-id"];
@ -1219,4 +1224,41 @@ class Probe {
return $data;
}
/**
* @brief Mix two paths together to possibly fix missing parts
*
* @param string $avatar Path to the avatar
* @param string $base Another path that is hopefully complete
*
* @return string fixed avatar path
*/
public static function fix_avatar($avatar, $base) {
$base_parts = parse_url($base);
// Remove all parts that could create a problem
unset($base_parts['path']);
unset($base_parts['query']);
unset($base_parts['fragment']);
$avatar_parts = parse_url($avatar);
// Now we mix them
$parts = array_merge($base_parts, $avatar_parts);
// And put them together again
$scheme = isset($parts['scheme']) ? $parts['scheme'] . '://' : '';
$host = isset($parts['host']) ? $parts['host'] : '';
$port = isset($parts['port']) ? ':' . $parts['port'] : '';
$path = isset($parts['path']) ? $parts['path'] : '';
$query = isset($parts['query']) ? '?' . $parts['query'] : '';
$fragment = isset($parts['fragment']) ? '#' . $parts['fragment'] : '';
$fixed = $scheme.$host.$port.$path.$query.$fragment;
logger('Base: '.$base.' - Avatar: '.$avatar.' - Fixed: '.$fixed, LOGGER_DATA);
return $fixed;
}
}

View File

@ -545,7 +545,7 @@ function acl_lookup(App $a, $out_type = 'json') {
if ($type == '') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `forum`, `prv` FROM `contact`
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
AND NOT (`network` IN ('%s', '%s'))
$sql_extra2
@ -554,7 +554,7 @@ function acl_lookup(App $a, $out_type = 'json') {
dbesc(NETWORK_OSTATUS), dbesc(NETWORK_STATUSNET)
);
} elseif ($type == 'c') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `forum`, `prv` FROM `contact`
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
AND NOT (`network` IN ('%s'))
$sql_extra2
@ -564,7 +564,7 @@ function acl_lookup(App $a, $out_type = 'json') {
);
}
elseif ($type == 'm') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag` FROM `contact`
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr` FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive`
AND `network` IN ('%s','%s','%s')
$sql_extra2
@ -575,7 +575,7 @@ function acl_lookup(App $a, $out_type = 'json') {
dbesc(NETWORK_DIASPORA)
);
} elseif ($type == 'a') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `forum`, `prv` FROM `contact`
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
WHERE `uid` = %d AND `pending` = 0
$sql_extra2
ORDER BY `name` ASC ",
@ -619,6 +619,7 @@ function acl_lookup(App $a, $out_type = 'json') {
'network' => $g['network'],
'link' => $g['url'],
'nick' => htmlentities(($g['attag']) ? $g['attag'] : $g['nick']),
'addr' => htmlentities(($g['addr']) ? $g['addr'] : $g['url']),
'forum' => ((x($g, 'forum') || x($g, 'prv')) ? 1 : 0),
);
}
@ -663,6 +664,7 @@ function acl_lookup(App $a, $out_type = 'json') {
'network' => $contact['network'],
'link' => $contact['url'],
'nick' => htmlentities($contact['nick'] ? : $contact['addr']),
'addr' => htmlentities(($contact['addr']) ? $contact['addr'] : $contact['url']),
'forum' => $contact['forum']
);
}

View File

@ -526,6 +526,15 @@ $called_api = null;
}
}
if (is_null($user) && x($_GET, 'profileurl')) {
$user = dbesc(normalise_link($_GET['profileurl']));
$nick = $user;
$extra_query = "AND `contact`.`nurl` = '%s' ";
if (api_user() !== false) {
$extra_query .= "AND `contact`.`uid`=".intval(api_user());
}
}
if (is_null($user) AND ($a->argc > (count($called_api) - 1)) AND (count($called_api) > 0)) {
$argid = count($called_api);
list($user, $null) = explode(".", $a->argv[$argid]);
@ -1401,6 +1410,7 @@ $called_api = null;
/// @TODO move to top of file or somewhere better
api_register_func('api/users/show','api_users_show');
api_register_func('api/externalprofile/show','api_users_show');
function api_users_search($type) {

View File

@ -25,11 +25,20 @@ class dba {
private static $dbo;
private static $relation = array();
function __construct($server, $user, $pass, $db, $install = false) {
function __construct($serveraddr, $user, $pass, $db, $install = false) {
$a = get_app();
$stamp1 = microtime(true);
$serveraddr = trim($serveraddr);
$serverdata = explode(':', $serveraddr);
$server = $serverdata[0];
if (count($serverdata) > 1) {
$port = trim($serverdata[1]);
}
$server = trim($server);
$user = trim($user);
$pass = trim($pass);
@ -55,6 +64,11 @@ class dba {
if (class_exists('\PDO') && in_array('mysql', PDO::getAvailableDrivers())) {
$this->driver = 'pdo';
$connect = "mysql:host=".$server.";dbname=".$db;
if (isset($port)) {
$connect .= ";port=".$port;
}
if (isset($a->config["system"]["db_charset"])) {
$connect .= ";charset=".$a->config["system"]["db_charset"];
}
@ -64,7 +78,7 @@ class dba {
}
} elseif (class_exists('mysqli')) {
$this->driver = 'mysqli';
$this->db = @new mysqli($server,$user,$pass,$db);
$this->db = @new mysqli($server, $user, $pass, $db, $port);
if (!mysqli_connect_errno()) {
$this->connected = true;
@ -74,8 +88,8 @@ class dba {
}
} elseif (function_exists('mysql_connect')) {
$this->driver = 'mysql';
$this->db = mysql_connect($server,$user,$pass);
if ($this->db && mysql_select_db($db,$this->db)) {
$this->db = mysql_connect($serveraddr, $user, $pass);
if ($this->db && mysql_select_db($db, $this->db)) {
$this->connected = true;
if (isset($a->config["system"]["db_charset"])) {
@ -484,18 +498,28 @@ class dba {
unset($args[0]);
// When the second function parameter is an array then use this as the parameter array
if ((count($args) == 1) AND (is_array($args[1]))) {
if ((count($args) > 0) AND (is_array($args[1]))) {
$params = $args[1];
} else {
$params = $args;
}
// Renumber the array keys to be sure that they fit
$i = 0;
$args = array();
foreach ($params AS $param) {
$args[++$i] = $param;
}
}
if (!self::$dbo OR !self::$dbo->connected) {
return false;
}
if (substr_count($sql, '?') != count($args)) {
// Question: Should we continue or stop the query here?
logger('Parameter mismatch. Query "'.$sql.'" - Parameters '.print_r($args, true), LOGGER_DEBUG);
}
$sql = self::$dbo->any_value_fallback($sql);
if (x($a->config,'system') && x($a->config['system'], 'db_callstack')) {
@ -553,9 +577,10 @@ class dba {
$values[] = &$args[$param];
}
if (count($values) > 0) {
array_unshift($values, $params);
call_user_func_array(array($stmt, 'bind_param'), $values);
}
if (!$stmt->execute()) {
self::$dbo->error = self::$dbo->db->error;
@ -861,7 +886,7 @@ class dba {
logger(dba::replace_parameters($sql, $command['param']), LOGGER_DATA);
if (!self::e($sql, $param)) {
if (!self::e($sql, $command['param'])) {
self::p("ROLLBACK");
return false;
}
@ -889,7 +914,7 @@ class dba {
logger(dba::replace_parameters($sql, $field_values), LOGGER_DATA);
if (!self::e($sql, $param)) {
if (!self::e($sql, $field_values)) {
self::p("ROLLBACK");
return false;
}
@ -991,6 +1016,76 @@ class dba {
return self::e($sql, $params);
}
/**
* @brief Select rows from a table
*
* @param string $table Table name
* @param array $fields array of selected fields
* @param array $condition array of fields for condition
* @param array $params array of several parameters
*
* @return boolean|object If "limit" is equal "1" only a single row is returned, else a query object is returned
*
* Example:
* $table = "item";
* $fields = array("id", "uri", "uid", "network");
* $condition = array("uid" => 1, "network" => 'dspr');
* $params = array("order" => array("id", "received" => true), "limit" => 1);
*
* $data = dba::select($table, $fields, $condition, $params);
*/
static public function select($table, $fields = array(), $condition = array(), $params = array()) {
if ($table == '') {
return false;
}
if (count($fields) > 0) {
$select_fields = "`".implode("`, `", array_values($fields))."`";
} else {
$select_fields = "*";
}
if (count($condition) > 0) {
$condition_string = " WHERE `".implode("` = ? AND `", array_keys($condition))."` = ?";
} else {
$condition_string = "";
}
$param_string = '';
$single_row = false;
if (isset($params['order'])) {
$param_string .= " ORDER BY ";
foreach ($params['order'] AS $fields => $order) {
if (!is_int($fields)) {
$param_string .= "`".$fields."` ".($order ? "DESC" : "ASC").", ";
} else {
$param_string .= "`".$order."`, ";
}
}
$param_string = substr($param_string, 0, -2);
}
if (isset($params['limit'])) {
if (is_int($params['limit'])) {
$param_string .= " LIMIT ".$params['limit'];
$single_row =($params['limit'] == 1);
}
}
$sql = "SELECT ".$select_fields." FROM `".$table."`".$condition_string.$param_string;
$result = self::p($sql, $condition);
if (is_bool($result) OR !$single_row) {
return $result;
} else {
$row = self::fetch($result);
self::close($result);
return $row;
}
}
/**
* @brief Closes the current statement
*

View File

@ -399,6 +399,14 @@ function update_structure($verbose, $action, $tables=null, $definition=null) {
$sql3 .= ";";
}
$field_list = '';
if ($is_unique && $ignore == '') {
foreach ($structure['fields'] AS $fieldname => $parameters) {
$field_list .= 'ANY_VALUE(`' . $fieldname . '`),';
}
$field_list = rtrim($field_list, ',');
}
if ($verbose) {
// Ensure index conversion to unique removes duplicates
if ($is_unique) {
@ -415,7 +423,7 @@ function update_structure($verbose, $action, $tables=null, $definition=null) {
if ($ignore != "") {
echo "SET session old_alter_table=0;\n";
} else {
echo "INSERT INTO `".$temp_name."` SELECT * FROM `".$name."`".$group_by.";\n";
echo "INSERT INTO `".$temp_name."` SELECT ".$field_list." FROM `".$name."`".$group_by.";\n";
echo "DROP TABLE `".$name."`;\n";
echo "RENAME TABLE `".$temp_name."` TO `".$name."`;\n";
}
@ -446,7 +454,7 @@ function update_structure($verbose, $action, $tables=null, $definition=null) {
if ($ignore != "") {
$db->q("SET session old_alter_table=0;");
} else {
$r = $db->q("INSERT INTO `".$temp_name."` SELECT * FROM `".$name."`".$group_by.";");
$r = $db->q("INSERT INTO `".$temp_name."` SELECT ".$field_list." FROM `".$name."`".$group_by.";");
if (!dbm::is_result($r)) {
$errors .= print_update_error($db, $sql3);
return $errors;
@ -879,7 +887,7 @@ function db_definition() {
"indexes" => array(
"PRIMARY" => array("id"),
"addr" => array("addr(32)"),
"url" => array("url"),
"url" => array("UNIQUE", "url(190)"),
)
);
$database["ffinder"] = array(
@ -964,7 +972,7 @@ function db_definition() {
),
"indexes" => array(
"PRIMARY" => array("id"),
"nurl" => array("nurl(64)"),
"nurl" => array("UNIQUE", "nurl(190)"),
"name" => array("name(64)"),
"nick" => array("nick(32)"),
"addr" => array("addr(64)"),
@ -1034,7 +1042,7 @@ function db_definition() {
),
"indexes" => array(
"PRIMARY" => array("id"),
"nurl" => array("nurl(32)"),
"nurl" => array("UNIQUE", "nurl(190)"),
)
);
$database["hook"] = array(
@ -1219,6 +1227,7 @@ function db_definition() {
"convid" => array("convid"),
"uri" => array("uri(64)"),
"parent-uri" => array("parent-uri(64)"),
"contactid" => array("contact-id"),
)
);
$database["mailacct"] = array(
@ -1356,6 +1365,7 @@ function db_definition() {
),
"indexes" => array(
"PRIMARY" => array("id"),
"contactid" => array("contact-id"),
"uid_contactid" => array("uid", "contact-id"),
"uid_profile" => array("uid", "profile"),
"uid_album_scale_created" => array("uid", "album(32)", "scale", "created"),

View File

@ -188,7 +188,80 @@ class Diaspora {
}
/**
* @brief: Decodes incoming Diaspora message
* @brief: Decodes incoming Diaspora message in the new format
*
* @param array $importer Array of the importer user
* @param string $raw raw post message
*
* @return array
* 'message' -> decoded Diaspora XML message
* 'author' -> author diaspora handle
* 'key' -> author public key (converted to pkcs#8)
*/
public static function decode_raw($importer, $raw) {
$data = json_decode($raw);
// Is it a private post? Then decrypt the outer Salmon
if (is_object($data)) {
$encrypted_aes_key_bundle = base64_decode($data->aes_key);
$ciphertext = base64_decode($data->encrypted_magic_envelope);
$outer_key_bundle = '';
@openssl_private_decrypt($encrypted_aes_key_bundle, $outer_key_bundle, $importer['prvkey']);
$j_outer_key_bundle = json_decode($outer_key_bundle);
if (!is_object($j_outer_key_bundle)) {
logger('Outer Salmon did not verify. Discarding.');
http_status_exit(400);
}
$outer_iv = base64_decode($j_outer_key_bundle->iv);
$outer_key = base64_decode($j_outer_key_bundle->key);
$xml = diaspora::aes_decrypt($outer_key, $outer_iv, $ciphertext);
} else {
$xml = $raw;
}
$basedom = parse_xml_string($xml);
if (!is_object($basedom)) {
logger('Received data does not seem to be an XML. Discarding.');
http_status_exit(400);
}
$base = $basedom->children(NAMESPACE_SALMON_ME);
// Not sure if this cleaning is needed
$data = str_replace(array(" ", "\t", "\r", "\n"), array("", "", "", ""), $base->data);
// Build the signed data
$type = $base->data[0]->attributes()->type[0];
$encoding = $base->encoding;
$alg = $base->alg;
$signed_data = $data.'.'.base64url_encode($type).'.'.base64url_encode($encoding).'.'.base64url_encode($alg);
// This is the signature
$signature = base64url_decode($base->sig);
// Get the senders' public key
$key_id = $base->sig[0]->attributes()->key_id[0];
$author_addr = base64_decode($key_id);
$key = diaspora::key($author_addr);
$verify = rsa_verify($signed_data, $signature, $key);
if (!$verify) {
logger('Message did not verify. Discarding.');
http_status_exit(400);
}
return array('message' => (string)base64url_decode($base->data),
'author' => unxmlify($author_addr),
'key' => (string)$key);
}
/**
* @brief: Decodes incoming Diaspora message in the deprecated format
*
* @param array $importer Array of the importer user
* @param string $xml urldecoded Diaspora salmon
@ -203,9 +276,10 @@ class Diaspora {
$public = false;
$basedom = parse_xml_string($xml);
if (!is_object($basedom))
if (!is_object($basedom)) {
logger("XML is not parseable.");
return false;
}
$children = $basedom->children('https://joindiaspora.com/protocol');
if ($children->header) {
@ -334,6 +408,24 @@ class Diaspora {
return false;
}
if (!($postdata = self::valid_posting($msg))) {
logger("Invalid posting");
return false;
}
$fields = $postdata['fields'];
// Is it a an action (comment, like, ...) for our own post?
if (isset($fields->parent_guid) AND !$postdata["relayed"]) {
$guid = notags(unxmlify($fields->parent_guid));
$importer = self::importer_for_guid($guid);
if (is_array($importer)) {
logger("delivering to origin: ".$importer["name"]);
$message_id = self::dispatch($importer, $msg, $fields);
return $message_id;
}
}
// Now distribute it to the followers
$r = q("SELECT `user`.* FROM `user` WHERE `user`.`uid` IN
(SELECT `contact`.`uid` FROM `contact` WHERE `contact`.`network` = '%s' AND `contact`.`addr` = '%s')
@ -345,13 +437,14 @@ class Diaspora {
if (dbm::is_result($r)) {
foreach ($r as $rr) {
logger("delivering to: ".$rr["username"]);
self::dispatch($rr,$msg);
self::dispatch($rr, $msg, $fields);
}
} elseif (!Config::get('system', 'relay_subscribe', false)) {
logger("Unwanted message from ".$msg["author"]." send by ".$_SERVER["REMOTE_ADDR"]." with ".$_SERVER["HTTP_USER_AGENT"].": ".print_r($msg, true), LOGGER_DEBUG);
} else {
// Use a dummy importer to import the data for the public copy
// or for comments from unknown people
$importer = array("uid" => 0, "page-flags" => PAGE_FREELOVE);
$message_id = self::dispatch($importer,$msg);
$message_id = self::dispatch($importer, $msg, $fields);
}
return $message_id;
@ -362,27 +455,27 @@ class Diaspora {
*
* @param array $importer Array of the importer user
* @param array $msg The post that will be dispatched
* @param object $fields SimpleXML object that contains the message
*
* @return int The message id of the generated message, "true" or "false" if there was an error
*/
public static function dispatch($importer, $msg) {
public static function dispatch($importer, $msg, $fields = null) {
// The sender is the handle of the contact that sent the message.
// This will often be different with relayed messages (for example "like" and "comment")
$sender = $msg["author"];
if (!self::valid_posting($msg, $fields)) {
// This is only needed for private postings since this is already done for public ones before
if (is_null($fields)) {
if (!($postdata = self::valid_posting($msg))) {
logger("Invalid posting");
return false;
}
$fields = $postdata['fields'];
}
$type = $fields->getName();
$social_relay = Config::get('system', 'relay_subscribe', false);
if (!$social_relay AND ($type == 'message')) {
logger("Unwanted message from ".$sender." send by ".$_SERVER["REMOTE_ADDR"]." with ".$_SERVER["HTTP_USER_AGENT"].": ".print_r($msg, true), LOGGER_DEBUG);
}
logger("Received message type ".$type." from ".$sender." for user ".$importer["uid"], LOGGER_DEBUG);
switch ($type) {
@ -440,11 +533,10 @@ class Diaspora {
* It also does the conversion between the old and the new diaspora format.
*
* @param array $msg Array with the XML, the sender handle and the sender signature
* @param object $fields SimpleXML object that contains the posting when it is valid
*
* @return bool Is the posting valid?
* @return bool|array If the posting is valid then an array with an SimpleXML object is returned
*/
private static function valid_posting($msg, &$fields) {
private static function valid_posting($msg) {
$data = parse_xml_string($msg["message"], false);
@ -485,34 +577,40 @@ class Diaspora {
foreach ($element->children() AS $fieldname => $entry) {
if ($oldXML) {
// Translation for the old XML structure
if ($fieldname == "diaspora_handle")
if ($fieldname == "diaspora_handle") {
$fieldname = "author";
if ($fieldname == "participant_handles")
}
if ($fieldname == "participant_handles") {
$fieldname = "participants";
}
if (in_array($type, array("like", "participation"))) {
if ($fieldname == "target_type")
if ($fieldname == "target_type") {
$fieldname = "parent_type";
}
if ($fieldname == "sender_handle")
}
if ($fieldname == "sender_handle") {
$fieldname = "author";
if ($fieldname == "recipient_handle")
}
if ($fieldname == "recipient_handle") {
$fieldname = "recipient";
if ($fieldname == "root_diaspora_id")
}
if ($fieldname == "root_diaspora_id") {
$fieldname = "root_author";
}
if ($type == "status_message") {
if ($fieldname == "raw_message") {
$fieldname = "text";
}
}
if ($type == "retraction") {
if ($fieldname == "post_guid")
if ($fieldname == "post_guid") {
$fieldname = "target_guid";
if ($fieldname == "type")
}
if ($fieldname == "type") {
$fieldname = "target_type";
}
}
}
if (($fieldname == "author_signature") AND ($entry != ""))
$author_signature = base64_decode($entry);
@ -539,9 +637,9 @@ class Diaspora {
}
// Only some message types have signatures. So we quit here for the other types.
if (!in_array($type, array("comment", "message", "like")))
return true;
if (!in_array($type, array("comment", "like"))) {
return array("fields" => $fields, "relayed" => false);
}
// No author_signature? This is a must, so we quit.
if (!isset($author_signature)) {
logger("No author signature for type ".$type." - Message: ".$msg["message"], LOGGER_DEBUG);
@ -549,12 +647,16 @@ class Diaspora {
}
if (isset($parent_author_signature)) {
$relayed = true;
$key = self::key($msg["author"]);
if (!rsa_verify($signed_data, $parent_author_signature, $key, "sha256")) {
logger("No valid parent author signature for parent author ".$msg["author"]. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$parent_author_signature, LOGGER_DEBUG);
return false;
}
} else {
$relayed = false;
}
$key = self::key($fields->author);
@ -562,8 +664,9 @@ class Diaspora {
if (!rsa_verify($signed_data, $author_signature, $key, "sha256")) {
logger("No valid author signature for author ".$fields->author. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$author_signature, LOGGER_DEBUG);
return false;
} else
return true;
} else {
return array("fields" => $fields, "relayed" => $relayed);
}
}
/**
@ -592,7 +695,7 @@ class Diaspora {
*
* @return array the queried data
*/
private static function person_by_handle($handle) {
public static function person_by_handle($handle) {
$r = q("SELECT * FROM `fcontact` WHERE `network` = '%s' AND `addr` = '%s' LIMIT 1",
dbesc(NETWORK_DIASPORA),
@ -829,17 +932,20 @@ class Diaspora {
logger("defining user ".$contact["nick"]." as friend");
}
if (($contact["blocked"]) || ($contact["readonly"]) || ($contact["archive"]))
// We don't seem to like that person
if ($contact["blocked"] || $contact["readonly"] || $contact["archive"]) {
return false;
if ($contact["rel"] == CONTACT_IS_SHARING || $contact["rel"] == CONTACT_IS_FRIEND)
// We are following this person? Then it is okay
} elseif (($contact["rel"] == CONTACT_IS_SHARING) || ($contact["rel"] == CONTACT_IS_FRIEND)) {
return true;
if ($contact["rel"] == CONTACT_IS_FOLLOWER)
if (($importer["page-flags"] == PAGE_COMMUNITY) OR $is_comment)
// Is it a post to a community? That's good
} elseif (($contact["rel"] == CONTACT_IS_FOLLOWER) && ($importer["page-flags"] == PAGE_COMMUNITY)) {
return true;
// Messages for the global users are always accepted
if ($importer["uid"] == 0)
}
// Messages for the global users and comments are always accepted
if (($importer["uid"] == 0) || $is_comment) {
return true;
}
return false;
}
@ -857,8 +963,13 @@ class Diaspora {
$contact = self::contact_by_handle($importer["uid"], $handle);
if (!$contact) {
logger("A Contact for handle ".$handle." and user ".$importer["uid"]." was not found");
// If a contact isn't found, we accept it anyway if it is a comment
if ($is_comment) {
return $importer;
} else {
return false;
}
}
if (!self::post_allow($importer, $contact, $is_comment)) {
logger("The handle: ".$handle." is not allowed to post to user ".$importer["uid"]);
@ -1112,9 +1223,9 @@ class Diaspora {
$cid = $r[0]["id"];
$network = $r[0]["network"];
// We are receiving content from a user that is about to be terminated
// We are receiving content from a user that possibly is about to be terminated
// This means the user is vital, so we remove a possible termination date.
unmark_for_death($contact);
unmark_for_death($r[0]);
} else {
$cid = $contact["id"];
$network = NETWORK_DIASPORA;
@ -1229,24 +1340,23 @@ class Diaspora {
}
/**
* @brief Find the best importer for a comment
* @brief Find the best importer for a comment, like, ...
*
* @param array $importer Array of the importer user
* @param string $guid The guid of the item
*
* @return array the importer that fits the best
* @return array|boolean the origin owner of that post - or false
*/
private static function importer_for_comment($importer, $guid) {
private static function importer_for_guid($guid) {
$item = dba::fetch_first("SELECT `uid` FROM `item` WHERE `origin` AND `guid` = ? LIMIT 1", $guid);
if (dbm::is_result($item)) {
logger("Found user ".$item['uid']." as owner of item ".$guid, LOGGER_DEBUG);
$contact = dba::fetch_first("SELECT * FROM `contact` WHERE `self` AND `uid` = ?", $item['uid']);
if (dbm::is_result($contact)) {
$importer = $contact;
return $contact;
}
}
return $importer;
return false;
}
/**
@ -1260,10 +1370,10 @@ class Diaspora {
* @return int The message id of the generated comment or "false" if there was an error
*/
private static function receive_comment($importer, $sender, $data, $xml) {
$author = notags(unxmlify($data->author));
$guid = notags(unxmlify($data->guid));
$parent_guid = notags(unxmlify($data->parent_guid));
$text = unxmlify($data->text);
$author = notags(unxmlify($data->author));
if (isset($data->created_at)) {
$created_at = datetime_convert("UTC", "UTC", notags(unxmlify($data->created_at)));
@ -1278,11 +1388,6 @@ class Diaspora {
$thr_uri = "";
}
// Find the best importer when there was no importer found
if ($importer["uid"] == 0) {
$importer = self::importer_for_comment($importer, $parent_guid);
}
$contact = self::allowed_contact_by_handle($importer, $sender, true);
if (!$contact) {
return false;
@ -1383,16 +1488,9 @@ class Diaspora {
* @return bool "true" if it was successful
*/
private static function receive_conversation_message($importer, $contact, $data, $msg, $mesg, $conversation) {
$author = notags(unxmlify($data->author));
$guid = notags(unxmlify($data->guid));
$subject = notags(unxmlify($data->subject));
$author = notags(unxmlify($data->author));
$msg_guid = notags(unxmlify($mesg->guid));
$msg_parent_guid = notags(unxmlify($mesg->parent_guid));
$msg_parent_author_signature = notags(unxmlify($mesg->parent_author_signature));
$msg_author_signature = notags(unxmlify($mesg->author_signature));
$msg_text = unxmlify($mesg->text);
$msg_created_at = datetime_convert("UTC", "UTC", notags(unxmlify($mesg->created_at)));
// "diaspora_handle" is the element name from the old version
// "author" is the element name from the new version
@ -1404,7 +1502,10 @@ class Diaspora {
return false;
}
$msg_guid = notags(unxmlify($mesg->guid));
$msg_conversation_guid = notags(unxmlify($mesg->conversation_guid));
$msg_text = unxmlify($mesg->text);
$msg_created_at = datetime_convert("UTC", "UTC", notags(unxmlify($mesg->created_at)));
if ($msg_conversation_guid != $guid) {
logger("message conversation guid does not belong to the current conversation.");
@ -1414,42 +1515,8 @@ class Diaspora {
$body = diaspora2bb($msg_text);
$message_uri = $msg_author.":".$msg_guid;
$author_signed_data = $msg_guid.";".$msg_parent_guid.";".$msg_text.";".unxmlify($mesg->created_at).";".$msg_author.";".$msg_conversation_guid;
$author_signature = base64_decode($msg_author_signature);
if (strcasecmp($msg_author,$msg["author"]) == 0) {
$person = $contact;
$key = $msg["key"];
} else {
$person = self::person_by_handle($msg_author);
if (is_array($person) && x($person, "pubkey")) {
$key = $person["pubkey"];
} else {
logger("unable to find author details");
return false;
}
}
if (!rsa_verify($author_signed_data, $author_signature, $key, "sha256")) {
logger("verification failed.");
return false;
}
if ($msg_parent_author_signature) {
$owner_signed_data = $msg_guid.";".$msg_parent_guid.";".$msg_text.";".unxmlify($mesg->created_at).";".$msg_author.";".$msg_conversation_guid;
$parent_author_signature = base64_decode($msg_parent_author_signature);
$key = $msg["key"];
if (!rsa_verify($owner_signed_data, $parent_author_signature, $key, "sha256")) {
logger("owner verification failed.");
return false;
}
}
$r = q("SELECT `id` FROM `mail` WHERE `uri` = '%s' LIMIT 1",
dbesc($message_uri)
);
@ -1508,10 +1575,10 @@ class Diaspora {
* @return bool Success
*/
private static function receive_conversation($importer, $msg, $data) {
$author = notags(unxmlify($data->author));
$guid = notags(unxmlify($data->guid));
$subject = notags(unxmlify($data->subject));
$created_at = datetime_convert("UTC", "UTC", notags(unxmlify($data->created_at)));
$author = notags(unxmlify($data->author));
$participants = notags(unxmlify($data->participants));
$messages = $data->message;
@ -1616,11 +1683,11 @@ class Diaspora {
* @return int The message id of the generated like or "false" if there was an error
*/
private static function receive_like($importer, $sender, $data) {
$positive = notags(unxmlify($data->positive));
$guid = notags(unxmlify($data->guid));
$parent_type = notags(unxmlify($data->parent_type));
$parent_guid = notags(unxmlify($data->parent_guid));
$author = notags(unxmlify($data->author));
$guid = notags(unxmlify($data->guid));
$parent_guid = notags(unxmlify($data->parent_guid));
$parent_type = notags(unxmlify($data->parent_type));
$positive = notags(unxmlify($data->positive));
// likes on comments aren't supported by Diaspora - only on posts
// But maybe this will be supported in the future, so we will accept it.
@ -1715,12 +1782,11 @@ class Diaspora {
* @return bool Success?
*/
private static function receive_message($importer, $data) {
$author = notags(unxmlify($data->author));
$guid = notags(unxmlify($data->guid));
$parent_guid = notags(unxmlify($data->parent_guid));
$conversation_guid = notags(unxmlify($data->conversation_guid));
$text = unxmlify($data->text);
$created_at = datetime_convert("UTC", "UTC", notags(unxmlify($data->created_at)));
$author = notags(unxmlify($data->author));
$conversation_guid = notags(unxmlify($data->conversation_guid));
$contact = self::allowed_contact_by_handle($importer, $author, true);
if (!$contact) {
@ -1775,7 +1841,7 @@ class Diaspora {
0,
1,
dbesc($message_uri),
dbesc($author.":".$parent_guid),
dbesc($author.":".$conversation["guid"]),
dbesc($created_at)
);
@ -1844,9 +1910,9 @@ class Diaspora {
$name = unxmlify($data->first_name).((strlen($data->last_name)) ? " ".unxmlify($data->last_name) : "");
$image_url = unxmlify($data->image_url);
$birthday = unxmlify($data->birthday);
$location = diaspora2bb(unxmlify($data->location));
$about = diaspora2bb(unxmlify($data->bio));
$gender = unxmlify($data->gender);
$about = diaspora2bb(unxmlify($data->bio));
$location = diaspora2bb(unxmlify($data->location));
$searchable = (unxmlify($data->searchable) == "true");
$nsfw = (unxmlify($data->nsfw) == "true");
$tags = unxmlify($data->tag_string);
@ -2266,12 +2332,13 @@ class Diaspora {
* @return int the message id
*/
private static function receive_reshare($importer, $data, $xml) {
$author = notags(unxmlify($data->author));
$guid = notags(unxmlify($data->guid));
$created_at = datetime_convert("UTC", "UTC", notags(unxmlify($data->created_at)));
$root_author = notags(unxmlify($data->root_author));
$root_guid = notags(unxmlify($data->root_guid));
$guid = notags(unxmlify($data->guid));
$author = notags(unxmlify($data->author));
/// @todo handle unprocessed property "provider_display_name"
$public = notags(unxmlify($data->public));
$created_at = datetime_convert("UTC", "UTC", notags(unxmlify($data->created_at)));
$contact = self::allowed_contact_by_handle($importer, $author, false);
if (!$contact) {
@ -2346,9 +2413,9 @@ class Diaspora {
* @return bool success
*/
private static function item_retraction($importer, $contact, $data) {
$target_type = notags(unxmlify($data->target_type));
$target_guid = notags(unxmlify($data->target_guid));
$author = notags(unxmlify($data->author));
$target_guid = notags(unxmlify($data->target_guid));
$target_type = notags(unxmlify($data->target_type));
$person = self::person_by_handle($author);
if (!is_array($person)) {
@ -2356,11 +2423,16 @@ class Diaspora {
return false;
}
if (!isset($contact["url"])) {
$contact["url"] = $person["url"];
}
$r = q("SELECT `id`, `parent`, `parent-uri`, `author-link` FROM `item` WHERE `guid` = '%s' AND `uid` = %d AND NOT `file` LIKE '%%[%%' LIMIT 1",
dbesc($target_guid),
intval($importer["uid"])
);
if (!$r) {
logger("Target guid ".$target_guid." was not found for user ".$importer["uid"]);
return false;
}
@ -2406,7 +2478,7 @@ class Diaspora {
$target_type = notags(unxmlify($data->target_type));
$contact = self::contact_by_handle($importer["uid"], $sender);
if (!$contact) {
if (!$contact AND (in_array($target_type, array("Contact", "Person")))) {
logger("cannot find contact for sender: ".$sender." and user ".$importer["uid"]);
return false;
}
@ -2419,7 +2491,7 @@ class Diaspora {
case "Post": // "Post" will be supported in a future version
case "Reshare":
case "StatusMessage":
return self::item_retraction($importer, $contact, $data);;
return self::item_retraction($importer, $contact, $data);
case "Contact":
case "Person":
@ -2445,19 +2517,13 @@ class Diaspora {
* @return int The message id of the newly created item
*/
private static function receive_status_message($importer, $data, $xml) {
$raw_message = unxmlify($data->raw_message);
$guid = notags(unxmlify($data->guid));
$author = notags(unxmlify($data->author));
$public = notags(unxmlify($data->public));
$guid = notags(unxmlify($data->guid));
$created_at = datetime_convert("UTC", "UTC", notags(unxmlify($data->created_at)));
$public = notags(unxmlify($data->public));
$text = unxmlify($data->text);
$provider_display_name = notags(unxmlify($data->provider_display_name));
/// @todo enable support for polls
//if ($data->poll) {
// foreach ($data->poll AS $poll)
// print_r($poll);
// die("poll!\n");
//}
$contact = self::allowed_contact_by_handle($importer, $author, false);
if (!$contact) {
return false;
@ -2475,7 +2541,7 @@ class Diaspora {
}
}
$body = diaspora2bb($raw_message);
$body = diaspora2bb($text);
$datarray = array();
@ -2496,6 +2562,15 @@ class Diaspora {
}
}
/// @todo enable support for polls
//if ($data->poll) {
// foreach ($data->poll AS $poll)
// print_r($poll);
// die("poll!\n");
//}
/// @todo enable support for events
$datarray["uid"] = $importer["uid"];
$datarray["contact-id"] = $contact["id"];
$datarray["network"] = NETWORK_DIASPORA;

View File

@ -4,6 +4,7 @@
*/
use Friendica\App;
use Friendica\Core\Config;
require_once("include/Contact.php");
require_once("include/threads.php");
@ -29,42 +30,6 @@ class ostatus {
const OSTATUS_DEFAULT_POLL_TIMEFRAME = 1440; // given in minutes
const OSTATUS_DEFAULT_POLL_TIMEFRAME_MENTIONS = 14400; // given in minutes
/**
* @brief Mix two paths together to possibly fix missing parts
*
* @param string $avatar Path to the avatar
* @param string $base Another path that is hopefully complete
*
* @return string fixed avatar path
*/
public static function fix_avatar($avatar, $base) {
$base_parts = parse_url($base);
// Remove all parts that could create a problem
unset($base_parts['path']);
unset($base_parts['query']);
unset($base_parts['fragment']);
$avatar_parts = parse_url($avatar);
// Now we mix them
$parts = array_merge($base_parts, $avatar_parts);
// And put them together again
$scheme = isset($parts['scheme']) ? $parts['scheme'] . '://' : '';
$host = isset($parts['host']) ? $parts['host'] : '';
$port = isset($parts['port']) ? ':' . $parts['port'] : '';
$path = isset($parts['path']) ? $parts['path'] : '';
$query = isset($parts['query']) ? '?' . $parts['query'] : '';
$fragment = isset($parts['fragment']) ? '#' . $parts['fragment'] : '';
$fixed = $scheme.$host.$port.$path.$query.$fragment;
logger('Base: '.$base.' - Avatar: '.$avatar.' - Fixed: '.$fixed, LOGGER_DATA);
return $fixed;
}
/**
* @brief Fetches author data
*
@ -81,23 +46,43 @@ class ostatus {
$author = array();
$author["author-link"] = $xpath->evaluate('atom:author/atom:uri/text()', $context)->item(0)->nodeValue;
$author["author-name"] = $xpath->evaluate('atom:author/atom:name/text()', $context)->item(0)->nodeValue;
$addr = $xpath->evaluate('atom:author/atom:email/text()', $context)->item(0)->nodeValue;
$aliaslink = $author["author-link"];
$alternate = $xpath->query("atom:author/atom:link[@rel='alternate']", $context)->item(0)->attributes;
if (is_object($alternate))
foreach($alternate AS $attributes)
if ($attributes->name == "href")
if (is_object($alternate)) {
foreach ($alternate AS $attributes) {
if (($attributes->name == "href") AND ($attributes->textContent != "")) {
$author["author-link"] = $attributes->textContent;
}
}
}
$author["contact-id"] = $contact["id"];
if ($author["author-link"] != "") {
if ($aliaslink == "") {
$aliaslink = $author["author-link"];
}
$r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `nurl` IN ('%s', '%s') AND `network` != '%s'",
intval($importer["uid"]), dbesc(normalise_link($author["author-link"])),
dbesc(normalise_link($aliaslink)), dbesc(NETWORK_STATUSNET));
if ($r) {
if (dbm::is_result($r)) {
$contact = $r[0];
$author["contact-id"] = $r[0]["id"];
} else
$author["author-link"] = $r[0]["url"];
}
} elseif ($addr != "") {
// Should not happen
$contact = dba::fetch_first("SELECT * FROM `contact` WHERE `uid` = ? AND `addr` = ? AND `network` != ?",
$importer["uid"], $addr, NETWORK_STATUSNET);
if (dbm::is_result($contact)) {
$author["contact-id"] = $contact["id"];
$author["author-link"] = $contact["url"];
}
}
$avatarlist = array();
$avatars = $xpath->query("atom:author/atom:link[@rel='avatar']", $context);
@ -115,7 +100,7 @@ class ostatus {
}
if (count($avatarlist) > 0) {
krsort($avatarlist);
$author["author-avatar"] = self::fix_avatar(current($avatarlist), $author["author-link"]);
$author["author-avatar"] = Probe::fix_avatar(current($avatarlist), $author["author-link"]);
}
$displayname = $xpath->evaluate('atom:author/poco:displayName/text()', $context)->item(0)->nodeValue;
@ -1176,7 +1161,7 @@ class ostatus {
$arr["owner-name"] = $single_conv->actor->portablecontacts_net->displayName;
$arr["owner-link"] = $actor;
$arr["owner-avatar"] = self::fix_avatar($single_conv->actor->image->url, $arr["owner-link"]);
$arr["owner-avatar"] = Probe::fix_avatar($single_conv->actor->image->url, $arr["owner-link"]);
$arr["author-name"] = $arr["owner-name"];
$arr["author-link"] = $arr["owner-link"];
@ -1241,7 +1226,7 @@ class ostatus {
$arr["author-name"] = $single_conv->object->actor->contact->displayName;
}
$arr["author-link"] = $single_conv->object->actor->url;
$arr["author-avatar"] = self::fix_avatar($single_conv->object->actor->image->url, $arr["author-link"]);
$arr["author-avatar"] = Probe::fix_avatar($single_conv->object->actor->image->url, $arr["author-link"]);
$arr["app"] = $single_conv->object->provider->displayName."#";
//$arr["verb"] = $single_conv->object->verb;
@ -2270,6 +2255,9 @@ class ostatus {
$root = self::add_header($doc, $owner);
foreach ($items AS $item) {
if (Config::get('system', 'ostatus_debug')) {
$item['body'] .= '🍼';
}
$entry = self::entry($doc, $item, $owner);
$root->appendChild($entry);
}
@ -2290,6 +2278,10 @@ class ostatus {
$doc = new DOMDocument('1.0', 'utf-8');
$doc->formatOutput = true;
if (Config::get('system', 'ostatus_debug')) {
$item['body'] .= '🐟';
}
$entry = self::entry($doc, $item, $owner, true);
$doc->appendChild($entry);

View File

@ -35,6 +35,9 @@ function handle_pubsubhubbub($id) {
else
$rr = $r[0];
/// @todo Check server status with poco_check_server()
// Before this can be done we need a way to safely detect the server url.
logger("Generate feed of user ".$rr['nickname']." to ".$rr['callback_url']." - last updated ".$rr['last_update'], LOGGER_DEBUG);
$params = ostatus::feed($a, $rr['nickname'], $rr['last_update']);

View File

@ -1009,6 +1009,7 @@ function poco_check_server($server_url, $network = "", $force = false) {
if (dbm::is_result($servers) AND ($orig_server_url == $server_url) AND
($serverret['errno'] == CURLE_OPERATION_TIMEDOUT)) {
logger("Connection to server ".$server_url." timed out.", LOGGER_DEBUG);
dba::p("UPDATE `gserver` SET `last_failure` = ? WHERE `nurl` = ?", datetime_convert(), normalise_link($server_url));
return false;
}
@ -1023,6 +1024,7 @@ function poco_check_server($server_url, $network = "", $force = false) {
// Quit if there is a timeout
if ($serverret['errno'] == CURLE_OPERATION_TIMEDOUT) {
logger("Connection to server ".$server_url." timed out.", LOGGER_DEBUG);
dba::p("UPDATE `gserver` SET `last_failure` = ? WHERE `nurl` = ?", datetime_convert(), normalise_link($server_url));
return false;
}
@ -1032,12 +1034,10 @@ function poco_check_server($server_url, $network = "", $force = false) {
if (!$serverret["success"] OR ($serverret["body"] == "") OR (sizeof($xmlobj) == 0) OR !is_object($xmlobj)) {
// Workaround for bad configured servers (known nginx problem)
if (!in_array($serverret["debug"]["http_code"], array("403", "404"))) {
$last_failure = datetime_convert();
$failure = true;
}
$possible_failure = true;
} elseif ($network == NETWORK_DIASPORA)
$last_contact = datetime_convert();
}
// If the server has no possible failure we reset the cached data
if (!$possible_failure) {
@ -1055,8 +1055,6 @@ function poco_check_server($server_url, $network = "", $force = false) {
$data = json_decode($serverret["body"]);
if (isset($data->totalResults)) {
$poco = $server_url."/poco";
$last_contact = datetime_convert();
$server = poco_detect_poco_data($data);
if ($server) {
$platform = $server['platform'];
@ -1073,7 +1071,6 @@ function poco_check_server($server_url, $network = "", $force = false) {
$serverret = z_fetch_url($server_url);
if (!$serverret["success"] OR ($serverret["body"] == "")) {
$last_failure = datetime_convert();
$failure = true;
} else {
$server = poco_detect_server_type($serverret["body"]);
@ -1082,7 +1079,6 @@ function poco_check_server($server_url, $network = "", $force = false) {
$network = $server['network'];
$version = $server['version'];
$site_name = $server['site_name'];
$last_contact = datetime_convert();
}
$lines = explode("\n",$serverret["header"]);
@ -1096,15 +1092,11 @@ function poco_check_server($server_url, $network = "", $force = false) {
$network = NETWORK_DIASPORA;
$versionparts = explode("-", $version);
$version = $versionparts[0];
$last_contact = datetime_convert();
}
if(stristr($line,'Server: Mastodon')) {
$platform = "Mastodon";
$network = NETWORK_OSTATUS;
// Mastodon doesn't reveal version numbers
$version = "";
$last_contact = datetime_convert();
}
}
}
@ -1123,7 +1115,6 @@ function poco_check_server($server_url, $network = "", $force = false) {
$version = str_replace(chr(239).chr(187).chr(191), "", $serverret["body"]);
$version = trim($version, '"');
$network = NETWORK_OSTATUS;
$last_contact = datetime_convert();
}
// Test for GNU Social
@ -1135,7 +1126,19 @@ function poco_check_server($server_url, $network = "", $force = false) {
$version = str_replace(chr(239).chr(187).chr(191), "", $serverret["body"]);
$version = trim($version, '"');
$network = NETWORK_OSTATUS;
$last_contact = datetime_convert();
}
// Test for Mastodon
$serverret = z_fetch_url($server_url."/api/v1/instance");
if ($serverret["success"] AND ($serverret["body"] != '')) {
$data = json_decode($serverret["body"]);
if (isset($data->version)) {
$platform = "Mastodon";
$version = $data->version;
$site_name = $data->title;
$info = $data->description;
$network = NETWORK_OSTATUS;
}
}
}
@ -1145,8 +1148,6 @@ function poco_check_server($server_url, $network = "", $force = false) {
if ($serverret["success"]) {
$data = json_decode($serverret["body"]);
if (isset($data->site->server)) {
$last_contact = datetime_convert();
if (isset($data->site->platform)) {
$platform = $data->site->platform->PLATFORM_NAME;
$version = $data->site->platform->STD_VERSION;
@ -1193,7 +1194,6 @@ function poco_check_server($server_url, $network = "", $force = false) {
}
}
// Query statistics.json. Optional package for Diaspora, Friendica and Redmatrix
if (!$failure) {
$serverret = z_fetch_url($server_url."/statistics.json");
@ -1221,9 +1221,6 @@ function poco_check_server($server_url, $network = "", $force = false) {
} else {
$register_policy = REGISTER_CLOSED;
}
if (isset($data->version))
$last_contact = datetime_convert();
}
}
@ -1248,8 +1245,6 @@ function poco_check_server($server_url, $network = "", $force = false) {
if (isset($server['site_name'])) {
$site_name = $server['site_name'];
}
$last_contact = datetime_convert();
}
}
@ -1265,7 +1260,6 @@ function poco_check_server($server_url, $network = "", $force = false) {
$data = json_decode($serverret["body"]);
if (isset($data->version)) {
$last_contact = datetime_convert();
$network = NETWORK_DFRN;
$noscrape = $data->no_scrape_url;
@ -1291,13 +1285,14 @@ function poco_check_server($server_url, $network = "", $force = false) {
}
if ($possible_failure AND !$failure) {
$last_failure = datetime_convert();
$failure = true;
}
if ($failure) {
$last_contact = $orig_last_contact;
$last_failure = datetime_convert();
} else {
$last_contact = datetime_convert();
$last_failure = $orig_last_failure;
}

View File

@ -78,22 +78,26 @@ function contact_format(item) {
}
function editor_replace(item) {
if(typeof item.replace !== 'undefined') {
if (typeof item.replace !== 'undefined') {
return '$1$2' + item.replace;
}
if (typeof item.addr !== 'undefined') {
return '$1$2' + item.addr + ' ';
}
// $2 ensures that prefix (@,@!) is preserved
var id = item.id;
// don't add the id if it is empty (the id empty eg. if there are unknow contacts in thread)
if(id.length < 1)
if (id.length < 1) {
return '$1$2' + item.nick.replace(' ', '') + ' ';
}
// 16 chars of hash should be enough. Full hash could be used if it can be done in a visually appealing way.
// 16 chars is also the minimum length in the backend (otherwise it's interpreted as a local id).
if(id.length > 16)
if (id.length > 16) {
id = item.id.substring(0,16);
}
return '$1$2' + item.nick.replace(' ', '') + '+' + id + ' ';
}

View File

@ -279,7 +279,7 @@ function admin_page_blocklist(App $a) {
$blocklistform[] = array(
'domain' => array("domain[$id]", t('Blocked domain'), $b['domain'], '', t('The blocked domain'), 'required', '', ''),
'reason' => array("reason[$id]", t("Reason for the block"), $b['reason'], t('The reason why you blocked this domain.').'('.$b['domain'].')', 'required', '', ''),
'delete' => array("delete[$id]", t("Delete domain").' ('.$b['domain'].')', False , "Check to delete this entry from the blocklist")
'delete' => array("delete[$id]", t("Delete domain").' ('.$b['domain'].')', False , t("Check to delete this entry from the blocklist"))
);
}
}

View File

@ -262,7 +262,7 @@ function _contact_update_profile($contact_id) {
if ($uid != local_user())
return;
$data = probe_url($r[0]["url"]);
$data = Probe::uri($r[0]["url"], "", 0, false);
// "Feed" or "Unknown" is mostly a sign of communication problems
if ((in_array($data["network"], array(NETWORK_FEED, NETWORK_PHANTOM))) AND ($data["network"] != $r[0]["network"]))

View File

@ -11,29 +11,27 @@ require_once('include/crypto.php');
require_once('include/diaspora.php');
function receive_post(App $a) {
$enabled = intval(get_config('system','diaspora_enabled'));
if(! $enabled) {
$enabled = intval(get_config('system', 'diaspora_enabled'));
if (!$enabled) {
logger('mod-diaspora: disabled');
http_status_exit(500);
}
$public = false;
if(($a->argc == 2) && ($a->argv[1] === 'public')) {
if (($a->argc == 2) && ($a->argv[1] === 'public')) {
$public = true;
}
else {
} else {
if($a->argc != 3 || $a->argv[1] !== 'users')
if ($a->argc != 3 || $a->argv[1] !== 'users') {
http_status_exit(500);
}
$guid = $a->argv[2];
$r = q("SELECT * FROM `user` WHERE `guid` = '%s' AND `account_expired` = 0 AND `account_removed` = 0 LIMIT 1",
dbesc($guid)
);
if (! dbm::is_result($r)) {
if (!dbm::is_result($r)) {
http_status_exit(500);
}
@ -46,29 +44,34 @@ function receive_post(App $a) {
$xml = urldecode($_POST['xml']);
logger('mod-diaspora: new salmon ' . $xml, LOGGER_DATA);
if(! $xml)
if (!$xml) {
$postdata = file_get_contents("php://input");
if ($postdata == '') {
http_status_exit(500);
}
logger('mod-diaspora: message is okay', LOGGER_DEBUG);
$msg = Diaspora::decode($importer,$xml);
logger('mod-diaspora: message is in the new format', LOGGER_DEBUG);
$msg = Diaspora::decode_raw($importer, $postdata);
} else {
logger('mod-diaspora: message is in the old format', LOGGER_DEBUG);
$msg = Diaspora::decode($importer, $xml);
}
logger('mod-diaspora: decoded', LOGGER_DEBUG);
logger('mod-diaspora: decoded msg: ' . print_r($msg,true), LOGGER_DATA);
logger('mod-diaspora: decoded msg: ' . print_r($msg, true), LOGGER_DATA);
if(! is_array($msg))
if (!is_array($msg)) {
http_status_exit(500);
}
logger('mod-diaspora: dispatching', LOGGER_DEBUG);
$ret = 0;
if($public) {
if ($public) {
Diaspora::dispatch_public($msg);
} else {
$ret = Diaspora::dispatch($importer,$msg);
$ret = Diaspora::dispatch($importer, $msg);
}
http_status_exit(($ret) ? $ret : 200);

View File

@ -1,6 +1,6 @@
<?php
define('UPDATE_VERSION' , 1222);
define('UPDATE_VERSION' , 1224);
/**
*

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
<script>
// update pending count //
$(function(){
$("nav").bind('nav-update', function(e,data){
var elm = $('#pending-update');
var register = $(data).find('register').text();
if (register=="0") { register = ""; }
elm.html(register);
});
});
</script>
<div class="widget">
<h3><a href="{{$admurl}}">{{$admtxt}}</a></h3>
<ul role="menu">
{{foreach $subpages as $name => $item}}
<li role="menuitem" class="{{$item.2}}">
<a href="{{$item.0}}" {{if $item.accesskey}}accesskey="{{$item.accesskey}}"{{/if}}>
{{$item.1}}
{{if $name == "users"}}
<span id="pending-update" class="badge pull-right"></span>
{{/if}}
</a>
</li>
{{/foreach}}
</ul>
{{if $admin.update}}
<ul role="menu">
<li role="menuitem" class="{{$admin.update.2}}">
<a href="{{$admin.update.0}}" {{if $admin.update.accesskey}}accesskey="{{$admin.update.accesskey}}"{{/if}}>
{{$admin.update.1}}
</a>
</li>
</ul>
{{/if}}
</div>
{{if $admin.plugins_admin}}
<div class="widget">
<h3>{{$plugadmtxt}}</h3>
<ul role="menu">
{{foreach $admin.plugins_admin as $name => $item}}
<li role="menuitem" class="{{$item.2}}">
<a href="{{$item.0}}" {{if $item.accesskey}}accesskey="{{$item.accesskey}}"{{/if}}>
{{$item.1}}
</a>
</li>
{{/foreach}}
</ul>
</div>
{{/if}}
<div class="widget">
<h3>{{$logtxt}}</h3>
<ul role="menu">
<li role="menuitem" class="{{$admin.logs.2}}">
<a href="{{$admin.logs.0}}" {{if $admin.logs.accesskey}}accesskey="{{$admin.logs.accesskey}}"{{/if}}>
{{$admin.logs.1}}
</a>
</li>
<li role="menuitem" class="{{$admin.viewlogs.2}}">
<a href="{{$admin.viewlogs.0}}" {{if $admin.viewlogs.accesskey}}accesskey="{{$admin.viewlogs.accesskey}}"{{/if}}>
{{$admin.viewlogs.1}}
</a>
</li>
</ul>
</div>
<div class="widget">
<h3>{{$diagnosticstxt}}</h3>
<ul role="menu">
<li role="menuitem" class="{{$admin.diagnostics_probe.2}}">
<a href="{{$admin.diagnostics_probe.0}}" {{if $admin.diagnostics_probe.accesskey}}accesskey="{{$admin.diagnostics_probe.accesskey}}"{{/if}}>
{{$admin.diagnostics_probe.1}}
</a>
</li>
<li role="menuitem" class="{{$admin.diagnostics_webfinger.2}}">
<a href="{{$admin.diagnostics_webfinger.0}}" {{if $admin.viewlogs.accesskey}}accesskey="{{$admin.diagnostics_webfinger.accesskey}}"{{/if}}>
{{$admin.diagnostics_webfinger.1}}
</a>
</li>
</ul>
</div>

View File

@ -0,0 +1,12 @@
<div class="widget{{if $class}} {{$class}}{{/if}}">
{{if $title}}<h3>{{$title}}</h3>{{/if}}
{{if $desc}}<div class="desc">{{$desc}}</div>{{/if}}
<ul role="menu">
{{foreach $items as $item}}
<li role="menuitem" class="{{if $item.selected}}selected{{/if}}"><a href="{{$item.url}}" {{if $item.accesskey}}accesskey="{{$item.accesskey}}"{{/if}}>{{$item.label}}</a></li>
{{/foreach}}
</ul>
</div>