diff --git a/diaspora/Diaspora_Connection.php b/diaspora/Diaspora_Connection.php new file mode 100644 index 000000000..fae6432e2 --- /dev/null +++ b/diaspora/Diaspora_Connection.php @@ -0,0 +1,263 @@ + + * Modifications by Michael Vogel + */ + +class Diaspora_Connection { + private $user; + private $host; + private $password; + private $tls = true; //< Whether to use an SSL/TLS connection or not. + + private $last_http_result; //< Result of last cURL transaction. + private $csrf_token; //< Authenticity token retrieved from last HTTP response. + private $http_method; //< Which HTTP verb to use for the next HTTP request. + private $cookiejar; + + private $debug_log; + + public $provider = '*Diaspora Connection'; + + public function __construct($diaspora_handle = '', $password = '') { + if (!empty($diaspora_handle)) { + $this->setDiasporaID($diaspora_handle); + } + if (!empty($password)) { + $this->setPassword($password); + } + + $this->cookiejar = tempnam(sys_get_temp_dir(), 'cookies'); + return $this; + } + + public function __destruct() { + if (file_exists($this->cookiejar)) { + unlink($this->cookiejar); + } + } + + public function setDebugLog($log_file) { + $this->debug_log = $log_file; + } + + public function setDiasporaID($id) { + $parts = explode('@', $id); + $this->user = $parts[0]; + $this->host = $parts[1]; + } + + public function getDiasporaID() { + return $this->user . '@' . $this->host; + } + + public function getPodURL() { + return $this->getScheme() . '://' . $this->host; + } + + public function setPassword($passwd) { + $this->password = $passwd; + } + + public function setSecureTransport($is_secure) { + $this->tls = (bool) $is_secure; + } + + private function getScheme() { + return ($this->tls) ? 'https' : 'http'; + } + + private function doHttpRequest($url, $data = array(), $headers = array()) { + if (0 === strpos($url, '/')) { + $url = $this->getScheme() . '://' . $this->host . $url; + } + + $ch = curl_init($url); + + if ($this->debug_log) { + curl_setopt($ch, CURLOPT_VERBOSE, true); + $fh = fopen($this->debug_log, 'a'); + curl_setopt($ch, CURLOPT_STDERR, $fh); + } + + curl_setopt($ch, CURLOPT_HEADER, true); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + if (!empty($data)) { + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + } + if (!empty($headers)) { + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + } + + curl_setopt($ch, CURLOPT_COOKIEJAR, $this->cookiejar); + curl_setopt($ch, CURLOPT_COOKIEFILE, $this->cookiejar); + + // Are we doing a special kind of HTTP request? + switch ($this->http_method) { + case 'DELETE': + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->http_method); + break; + case 'POST': + curl_setopt($ch, CURLOPT_POST, true); + break; + } + + $this->last_http_result = new stdClass(); + $this->last_http_result->response = curl_exec($ch); + $this->last_http_result->info = curl_getinfo($ch); + curl_close($ch); + if (isset($fh)) { + fclose($fh); + } + + // Maybe update CSRF token + $token = $this->parseAuthenticityToken($this->last_http_result->response); + if ($token) { + $this->csrf_token = $token; + } + + return $this->last_http_result; + } + + private function doHttpDelete($url, $data = array(), $headers = array()) { + $this->http_method = 'DELETE'; + $this->doHttpRequest($url, $data, $headers); + $this->http_method = null; // reset for next request + } + + private function parseAuthenticityToken($str) { + $m = array(); + preg_match('/doHttpRequest('/users/sign_in'); + + $params = array( + 'user[username]' => $this->user, + 'user[password]' => $this->password, + 'authenticity_token' => $this->csrf_token + ); + $this->doHttpRequest('/users/sign_in', $params); + $this->doHttpRequest('/stream'); + return (200 === $this->last_http_result->info['http_code']) ? true : false; + } + + public function getAspects() { + $this->doHttpRequest('/bookmarklet'); + $m = array(); + preg_match('/"aspects"\:(\[.+?\])/', $this->last_http_result->response, $m); + return (!empty($m[1])) ? json_decode($m[1]) : false; + } + + public function getServices() { + $this->doHttpRequest('/bookmarklet'); + $m = array(); + preg_match('/"configured_services"\:(\[.+?\])/', $this->last_http_result->response, $m); + return (!empty($m[1])) ? json_decode($m[1]) : false; + } + + public function getNotifications($notification_type = '', $show = '') { + $url = '/notifications?format=json'; + + if (!empty($notification_type)) { + $url .= "&type=$notification_type"; + } + + if ('unread' === $show) { + $url .= '&show=unread'; + } + + $this->doHttpRequest($url); + return $this->readJsonResponse($this->last_http_result->response); + } + + public function getComments($post_id) { + $url = "/posts/$post_id/comments?format=json"; + $this->doHttpRequest($url); + return $this->readJsonResponse($this->last_http_result->response); + } + + public function postStatusMessage($msg, $aspect_ids = 'all_aspects', $additional_data = array()) { + $data = array( + 'aspect_ids' => $aspect_ids, + 'status_message' => array( + 'text' => $msg, + 'provider_display_name' => $this->provider + ) + ); + + if (!empty($additional_data)) { + $data += $additional_data; + } + + $headers = array( + 'Content-Type: application/json', + 'Accept: application/json', + 'X-CSRF-Token: ' . $this->csrf_token + ); + + $this->http_method = 'POST'; + $this->doHttpRequest('/status_messages', json_encode($data), $headers); + $this->http_method = null; // reset for next request + if (201 !== $this->last_http_result->info['http_code']) { + // TODO: Handle error. + return false; + } elseif (200 !== $this->last_http_result->info['http_code']) { + $resp = $this->readJsonResponse($this->last_http_result->response); + return $resp->id; + } + } + + public function postPhoto($file) { + $params = array( + 'photo[pending]' => 'true', + 'qqfile' => basename($file) + ); + $query_string = '?' . http_build_query($params); + $headers = array( + 'Accept: application/json', + 'X-Requested-With: XMLHttpRequest', + 'X-CSRF-Token: ' . $this->csrf_token, + 'X-File-Name: ' . basename($file), + 'Content-Type: application/octet-stream', + ); + if ($size = @filesize($file)) { + $headers[] = "Content-Length: $size"; + } + $data = file_get_contents($file); + $this->doHttpRequest('/photos' . $query_string, $data, $headers); + return $this->readJsonResponse($this->last_http_result->response); + } + + public function deletePost($id) { + $headers = array('X-CSRF-Token: ' . $this->csrf_token); + $this->doHttpDelete("/posts/$id", array(), $headers); + return (204 === $this->last_http_result->info['http_code']) ? true : false; + } + + public function deleteComment($id) { + $headers = array('X-CSRF-Token: ' . $this->csrf_token); + $this->doHttpDelete("/comments/$id", array(), $headers); + return (204 === $this->last_http_result->info['http_code']) ? true : false; + } + +} diff --git a/diaspora/diaspora.css b/diaspora/diaspora.css index 7c6d107d7..21ef9bc51 100755 --- a/diaspora/diaspora.css +++ b/diaspora/diaspora.css @@ -1,11 +1,11 @@ -#diaspora-enable-label, #diaspora-username-label, #diaspora-password-label, #diaspora-url-label, #diaspora-bydefault-label { +#diaspora-enable-label, #diaspora-username-label, #diaspora-password-label, #diaspora-bydefault-label, #diaspora-aspect-label { float: left; width: 200px; margin-top: 10px; } -#diaspora-checkbox, #diaspora-username, #diaspora-password, #diaspora-url, #diaspora-bydefault { +#diaspora-checkbox, #diaspora-username, #diaspora-password, #diaspora-bydefault, #diaspora-aspect { float: left; margin-top: 10px; } diff --git a/diaspora/diaspora.php b/diaspora/diaspora.php index 35234c390..aed80b88b 100755 --- a/diaspora/diaspora.php +++ b/diaspora/diaspora.php @@ -3,11 +3,12 @@ /** * Name: Diaspora Post Connector * Description: Post to Diaspora - * Version: 0.1 + * Version: 0.2 * Author: Michael Vogel - * Status: Unsupported */ +require_once("addon/diaspora/Diaspora_Connection.php"); + function diaspora_install() { register_hook('post_local', 'addon/diaspora/diaspora.php', 'diaspora_post_local'); register_hook('notifier_normal', 'addon/diaspora/diaspora.php', 'diaspora_send'); @@ -65,16 +66,14 @@ function diaspora_queue_hook(&$a,&$b) { $userdata = $r[0]; - $diaspora_username = get_pconfig($userdata['uid'],'diaspora','diaspora_username'); - $diaspora_password = get_pconfig($userdata['uid'],'diaspora','diaspora_password'); - $diaspora_url = get_pconfig($userdata['uid'],'diaspora','diaspora_url'); + $handle = get_pconfig($userdata['uid'],'diaspora','handle'); + $password = get_pconfig($userdata['uid'],'diaspora','password'); + $aspect = get_pconfig($userdata['uid'],'diaspora','aspect'); $success = false; - if($diaspora_url && $diaspora_username && $diaspora_password) { - require_once("addon/diaspora/diasphp.php"); - - logger('diaspora_queue: able to post for user '.$diaspora_username); + if ($handle && $password) { + logger('diaspora_queue: able to post for user '.$handle); $z = unserialize($x['content']); @@ -84,11 +83,12 @@ function diaspora_queue_hook(&$a,&$b) { try { logger('diaspora_queue: prepare', LOGGER_DEBUG); - $conn = new Diasphp($diaspora_url); - logger('diaspora_queue: try to log in '.$diaspora_username, LOGGER_DEBUG); - $conn->login($diaspora_username, $diaspora_password); + $conn = new Diaspora_Connection($handle, $password); + logger('diaspora_queue: try to log in '.$handle, LOGGER_DEBUG); + $conn->logIn(); logger('diaspora_queue: try to send '.$body, LOGGER_DEBUG); - $conn->post($post, $hostname); + $conn->provider = $hostname; + $conn->postStatusMessage($post, $aspect); logger('diaspora_queue: send '.$userdata['uid'].' success', LOGGER_DEBUG); @@ -127,20 +127,27 @@ function diaspora_settings(&$a,&$s) { $def_checked = (($def_enabled) ? ' checked="checked" ' : ''); - $diaspora_username = get_pconfig(local_user(), 'diaspora', 'diaspora_username'); - $diaspora_password = get_pconfig(local_user(), 'diaspora', 'diaspora_password'); - $diaspora_url = get_pconfig(local_user(), 'diaspora', 'diaspora_url'); + $handle = get_pconfig(local_user(), 'diaspora', 'handle'); + $password = get_pconfig(local_user(), 'diaspora', 'password'); + $aspect = get_pconfig(local_user(),'diaspora','aspect'); $status = ""; - if ($diaspora_username AND $diaspora_password AND $diaspora_url) { - try { - require_once("addon/diaspora/diasphp.php"); + $r = q("SELECT `addr` FROM `contact` WHERE `self` AND `uid` = %d", intval(local_user())); + if (dbm::is_result($r)) { + $status = sprintf(t("Please remember: You can always be reached from Diaspora with your Friendica handle %s. "), $r[0]['addr']); + $status .= t('This connector is only meant if you still want to use your old Diaspora account for some time. '); + $status .= sprintf(t('However, it is preferred that you tell your Diaspora contacts the new handle %s instead.'), $r[0]['addr']); + } - $conn = new Diasphp($diaspora_url); - $conn->login($diaspora_username, $diaspora_password); - } catch (Exception $e) { - $status = t("Can't login to your Diaspora account. Please check username and password and ensure you used the complete address (including http...)"); + $aspects = false; + + if ($handle AND $password) { + $conn = new Diaspora_Connection($handle, $password); + $conn->logIn(); + $aspects = $conn->getAspects(); + if (!$aspects) { + $status = t("Can't login to your Diaspora account. Please check handle (in the format user@domain.tld) and password."); } } @@ -166,19 +173,38 @@ function diaspora_settings(&$a,&$s) { $s .= '
'; $s .= '
'; - $s .= ''; - $s .= ''; + $s .= ''; + $s .= ''; $s .= '
'; $s .= '
'; $s .= ''; - $s .= ''; + $s .= ''; $s .= '
'; - $s .= '
'; - $s .= ''; - $s .= ''; - $s .= '
'; + if ($aspects) { + $single_aspect = new stdClass(); + $single_aspect->id = 'all_aspects'; + $single_aspect->name = t('All aspects'); + $aspects[] = $single_aspect; + + $single_aspect = new stdClass(); + $single_aspect->id = 'public'; + $single_aspect->name = t('Public'); + $aspects[] = $single_aspect; + + $s .= ''; + $s .= '"; + $s .= '
'; + } $s .= '
'; $s .= ''; @@ -198,10 +224,9 @@ function diaspora_settings_post(&$a,&$b) { set_pconfig(local_user(),'diaspora','post',intval($_POST['diaspora'])); set_pconfig(local_user(),'diaspora','post_by_default',intval($_POST['diaspora_bydefault'])); - set_pconfig(local_user(),'diaspora','diaspora_username',trim($_POST['diaspora_username'])); - set_pconfig(local_user(),'diaspora','diaspora_password',trim($_POST['diaspora_password'])); - set_pconfig(local_user(),'diaspora','diaspora_url',trim($_POST['diaspora_url'])); - + set_pconfig(local_user(),'diaspora','handle',trim($_POST['handle'])); + set_pconfig(local_user(),'diaspora','password',trim($_POST['password'])); + set_pconfig(local_user(),'diaspora','aspect',trim($_POST['aspect'])); } } @@ -251,11 +276,11 @@ function diaspora_send(&$a,&$b) { logger('diaspora_send: prepare posting', LOGGER_DEBUG); - $diaspora_username = get_pconfig($b['uid'],'diaspora','diaspora_username'); - $diaspora_password = get_pconfig($b['uid'],'diaspora','diaspora_password'); - $diaspora_url = get_pconfig($b['uid'],'diaspora','diaspora_url'); + $handle = get_pconfig($b['uid'],'diaspora','handle'); + $password = get_pconfig($b['uid'],'diaspora','password'); + $aspect = get_pconfig($b['uid'],'diaspora','aspect'); - if($diaspora_url && $diaspora_username && $diaspora_password) { + if ($handle && $password) { logger('diaspora_send: all values seem to be okay', LOGGER_DEBUG); @@ -301,13 +326,13 @@ function diaspora_send(&$a,&$b) { try { logger('diaspora_send: prepare', LOGGER_DEBUG); - $conn = new Diasphp($diaspora_url); - logger('diaspora_send: try to log in '.$diaspora_username, LOGGER_DEBUG); - $conn->login($diaspora_username, $diaspora_password); + $conn = new Diaspora_Connection($handle, $password); + logger('diaspora_send: try to log in '.$handle, LOGGER_DEBUG); + $conn->logIn(); logger('diaspora_send: try to send '.$body, LOGGER_DEBUG); - //throw new Exception('Test'); - $conn->post($body, $hostname); + $conn->provider = $hostname; + $conn->postStatusMessage($body, $aspect); logger('diaspora_send: success'); } catch (Exception $e) {