From dc4593f5b54112093c94cc2ea39a4f2d138c1432 Mon Sep 17 00:00:00 2001 From: Klaus Weidenbach Date: Sun, 12 Oct 2014 00:33:37 +0200 Subject: Moved classes from reddav.php into own files. Finished moving classes out from include/reddav.php into own files. Also continued with namespace for RedDAV. Improved some docs and added some todos and fixmes. --- include/RedDAV/RedBasicAuth.php | 208 +++++++++ include/RedDAV/RedBrowser.php | 17 +- include/RedDAV/RedDirectory.php | 461 ++++++++++++++++++++ include/RedDAV/RedFile.php | 275 ++++++++++++ include/reddav.php | 944 ++-------------------------------------- 5 files changed, 981 insertions(+), 924 deletions(-) create mode 100644 include/RedDAV/RedBasicAuth.php create mode 100644 include/RedDAV/RedDirectory.php create mode 100644 include/RedDAV/RedFile.php (limited to 'include') diff --git a/include/RedDAV/RedBasicAuth.php b/include/RedDAV/RedBasicAuth.php new file mode 100644 index 000000000..c1da73da1 --- /dev/null +++ b/include/RedDAV/RedBasicAuth.php @@ -0,0 +1,208 @@ +setAuthenticated($r[0]); + } + } + $r = q("SELECT * FROM channel WHERE channel_address = '%s' LIMIT 1", + dbesc($username) + ); + if ($r) { + $x = q("SELECT account_flags, account_salt, account_password FROM account WHERE account_id = %d LIMIT 1", + intval($r[0]['channel_account_id']) + ); + if ($x) { + // @fixme this foreach should not be needed? + foreach ($x as $record) { + if (($record['account_flags'] == ACCOUNT_OK) || ($record['account_flags'] == ACCOUNT_UNVERIFIED) + && (hash('whirlpool', $record['account_salt'] . $password) === $record['account_password'])) { + logger('(DAV) RedBasicAuth: password verified for ' . $username); + return $this->setAuthenticated($r[0]); + } + } + } + } + logger('(DAV) RedBasicAuth: password failed for ' . $username); + return false; + } + + /** + * @brief Sets variables and session parameters after successfull authentication. + * + * @param array $r + * Array with the values for the authenticated channel. + * @return bool + */ + protected function setAuthenticated($r) { + $this->channel_name = $r['channel_address']; + $this->channel_id = $r['channel_id']; + $this->channel_hash = $this->observer = $r['channel_hash']; + $_SESSION['uid'] = $r['channel_id']; + $_SESSION['account_id'] = $r['channel_account_id']; + $_SESSION['authenticated'] = true; + return true; + } + + /** + * Sets the channel_name from the currently logged-in channel. + * + * @param string $name + * The channel's name + */ + public function setCurrentUser($name) { + $this->channel_name = $name; + } + /** + * Returns information about the currently logged-in channel. + * + * If nobody is currently logged in, this method should return null. + * + * @see \Sabre\DAV\Auth\Backend\AbstractBasic::getCurrentUser + * @return string|null + */ + public function getCurrentUser() { + return $this->channel_name; + } + + /** + * @brief Sets the timezone from the channel in RedBasicAuth. + * + * Set in mod/cloud.php if the channel has a timezone set. + * + * @param string $timezone + * The channel's timezone. + * @return void + */ + public function setTimezone($timezone) { + $this->timezone = $timezone; + } + /** + * @brief Returns the timezone. + * + * @return string + * Return the channel's timezone. + */ + public function getTimezone() { + return $this->timezone; + } + + /** + * @brief Set browser plugin for SabreDAV. + * + * @see RedBrowser::set_writeable() + * @param DAV\Browser\Plugin $browser + */ + public function setBrowserPlugin($browser) { + $this->browser = $browser; + } + + /** + * Prints out all RedBasicAuth variables to logger(). + * + * @return void + */ + public function log() { + logger('dav: auth: channel_name ' . $this->channel_name, LOGGER_DATA); + logger('dav: auth: channel_id ' . $this->channel_id, LOGGER_DATA); + logger('dav: auth: channel_hash ' . $this->channel_hash, LOGGER_DATA); + logger('dav: auth: observer ' . $this->observer, LOGGER_DATA); + logger('dav: auth: owner_id ' . $this->owner_id, LOGGER_DATA); + logger('dav: auth: owner_nick ' . $this->owner_nick, LOGGER_DATA); + } +} \ No newline at end of file diff --git a/include/RedDAV/RedBrowser.php b/include/RedDAV/RedBrowser.php index 6639250ae..1f2550ac1 100644 --- a/include/RedDAV/RedBrowser.php +++ b/include/RedDAV/RedBrowser.php @@ -1,10 +1,4 @@ subscribeEvent()? + * @fixme It only disable/enable the visible parts. Not the POST handler + * which handels the actual requests when uploading files or creating folders. + * + * @todo Maybe this whole way of doing this can be solved with some + * $server->subscribeEvent(). */ public function set_writeable() { if (! $this->auth->owner_id) { diff --git a/include/RedDAV/RedDirectory.php b/include/RedDAV/RedDirectory.php new file mode 100644 index 000000000..72b0fe789 --- /dev/null +++ b/include/RedDAV/RedDirectory.php @@ -0,0 +1,461 @@ +ext_path = $ext_path; + // remove "/cloud" from the beginning of the path + $this->red_path = ((strpos($ext_path, '/cloud') === 0) ? substr($ext_path, 6) : $ext_path); + if (! $this->red_path) { + $this->red_path = '/'; + } + $this->auth = $auth_plugin; + $this->folder_hash = ''; + $this->getDir(); + + if ($this->auth->browser) { + $this->auth->browser->set_writeable(); + } + } + + private function log() { + logger('RedDirectory::log() ext_path ' . $this->ext_path, LOGGER_DATA); + logger('RedDirectory::log() os_path ' . $this->os_path, LOGGER_DATA); + logger('RedDirectory::log() red_path ' . $this->red_path, LOGGER_DATA); + } + + /** + * @brief Returns an array with all the child nodes. + * + * @throws DAV\Exception\Forbidden + * @return array DAV\INode[] + */ + public function getChildren() { + logger('RedDirectory::getChildren() called for ' . $this->ext_path, LOGGER_DATA); + $this->log(); + + if (get_config('system', 'block_public') && (! $this->auth->channel_id) && (! $this->auth->observer)) { + throw new DAV\Exception\Forbidden('Permission denied.'); + } + + if (($this->auth->owner_id) && (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'view_storage'))) { + throw new DAV\Exception\Forbidden('Permission denied.'); + } + + $contents = RedCollectionData($this->red_path, $this->auth); + return $contents; + } + + /** + * @brief Returns a child by name. + * + * + * @throw DAV\Exception\Forbidden + * @throw DAV\Exception\NotFound + * @param string $name + */ + public function getChild($name) { + logger('RedDirectory::getChild(): ' . $name, LOGGER_DATA); + + if (get_config('system', 'block_public') && (! $this->auth->channel_id) && (! $this->auth->observer)) { + throw new DAV\Exception\Forbidden('Permission denied.'); + } + + if (($this->auth->owner_id) && (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'view_storage'))) { + throw new DAV\Exception\Forbidden('Permission denied.'); + } + + if ($this->red_path === '/' && $name === 'cloud') { + return new RedDirectory('/cloud', $this->auth); + } + + $x = RedFileData($this->ext_path . '/' . $name, $this->auth); + if ($x) { + return $x; + } + + throw new DAV\Exception\NotFound('The file with name: ' . $name . ' could not be found.'); + } + + /** + * @brief Returns the name of the directory. + * + * @return string + */ + public function getName() { + logger('RedDirectory::getName() returns: ' . basename($this->red_path), LOGGER_DATA); + return (basename($this->red_path)); + } + + /** + * @brief Renames the directory. + * + * @todo handle duplicate directory name + * + * @throw DAV\Exception\Forbidden + * @param string $name The new name of the directory. + * @return void + */ + public function setName($name) { + logger('RedDirectory::setName(): ' . basename($this->red_path) . ' -> ' . $name, LOGGER_DATA); + + if ((! $name) || (! $this->auth->owner_id)) { + logger('RedDirectory::setName(): permission denied'); + throw new DAV\Exception\Forbidden('Permission denied.'); + } + + if (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage')) { + logger('RedDirectory::setName(): permission denied'); + throw new DAV\Exception\Forbidden('Permission denied.'); + } + + list($parent_path, ) = DAV\URLUtil::splitPath($this->red_path); + $new_path = $parent_path . '/' . $name; + + $r = q("UPDATE attach SET filename = '%s' WHERE hash = '%s' AND uid = %d LIMIT 1", + dbesc($name), + dbesc($this->folder_hash), + intval($this->auth->owner_id) + ); + + $this->red_path = $new_path; + } + + /** + * @brief Creates a new file in the directory. + * + * Data will either be supplied as a stream resource, or in certain cases + * as a string. Keep in mind that you may have to support either. + * + * After successful creation of the file, you may choose to return the ETag + * of the new file here. + * + * @throws DAV\Exception\Forbidden + * @param string $name Name of the file + * @param resource|string $data Initial payload + * @return null|string ETag + */ + public function createFile($name, $data = null) { + logger('RedDirectory::createFile(): ' . $name, LOGGER_DATA); + + if (! $this->auth->owner_id) { + logger('RedDirectory::createFile(): permission denied'); + throw new DAV\Exception\Forbidden('Permission denied.'); + } + + if (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage')) { + logger('RedDirectory::createFile(): permission denied'); + throw new DAV\Exception\Forbidden('Permission denied.'); + } + + $mimetype = z_mime_content_type($name); + + $c = q("SELECT * FROM channel WHERE channel_id = %d AND NOT (channel_pageflags & %d) LIMIT 1", + intval($this->auth->owner_id), + intval(PAGE_REMOVED) + ); + + if (! $c) { + logger('RedDirectory::createFile(): no channel'); + throw new DAV\Exception\Forbidden('Permission denied.'); + } + + $filesize = 0; + $hash = random_string(); + + $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, folder, flags, filetype, filesize, revision, data, created, edited, allow_cid, allow_gid, deny_cid, deny_gid ) + VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", + intval($c[0]['channel_account_id']), + intval($c[0]['channel_id']), + dbesc($hash), + dbesc($this->auth->observer), + dbesc($name), + dbesc($this->folder_hash), + dbesc(ATTACH_FLAG_OS), + dbesc($mimetype), + intval($filesize), + intval(0), + dbesc($this->os_path . '/' . $hash), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + dbesc($c[0]['channel_allow_cid']), + dbesc($c[0]['channel_allow_gid']), + dbesc($c[0]['channel_deny_cid']), + dbesc($c[0]['channel_deny_gid']) + ); + + $f = 'store/' . $this->auth->owner_nick . '/' . (($this->os_path) ? $this->os_path . '/' : '') . $hash; + + // returns the number of bytes that were written to the file, or FALSE on failure + $size = file_put_contents($f, $data); + // delete attach entry if file_put_contents() failed + if ($size === false) { + logger('RedDirectory::createFile(): file_put_contents() failed for ' . $name, LOGGER_DEBUG); + attach_delete($c[0]['channel_id'], $hash); + return; + } + + // returns now + $edited = datetime_convert(); + + // updates entry with filesize and timestamp + $d = q("UPDATE attach SET filesize = '%s', edited = '%s' WHERE hash = '%s' AND uid = %d LIMIT 1", + dbesc($size), + dbesc($edited), + dbesc($hash), + intval($c[0]['channel_id']) + ); + + // update the folder's lastmodified timestamp + $e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d LIMIT 1", + dbesc($edited), + dbesc($this->folder_hash), + intval($c[0]['channel_id']) + ); + + $maxfilesize = get_config('system', 'maxfilesize'); + if (($maxfilesize) && ($size > $maxfilesize)) { + attach_delete($c[0]['channel_id'], $hash); + return; + } + + // check against service class quota + $limit = service_class_fetch($c[0]['channel_id'], 'attach_upload_limit'); + if ($limit !== false) { + $x = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d ", + intval($c[0]['channel_account_id']) + ); + if (($x) && ($x[0]['total'] + $size > $limit)) { + logger('reddav: service class limit exceeded for ' . $c[0]['channel_name'] . ' total usage is ' . $x[0]['total'] . ' limit is ' . $limit); + attach_delete($c[0]['channel_id'], $hash); + return; + } + } + } + + /** + * @brief Creates a new subdirectory. + * + * @param string $name the directory to create + * @return void + */ + public function createDirectory($name) { + logger('RedDirectory::createDirectory(): ' . $name, LOGGER_DEBUG); + + if ((! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) { + throw new DAV\Exception\Forbidden('Permission denied.'); + } + + $r = q("SELECT * FROM channel WHERE channel_id = %d AND NOT (channel_pageflags & %d) LIMIT 1", + intval($this->auth->owner_id), + intval(PAGE_REMOVED) + ); + + if ($r) { + $result = attach_mkdir($r[0], $this->auth->observer, array('filename' => $name, 'folder' => $this->folder_hash)); + if (! $result['success']) { + logger('RedDirectory::createDirectory(): ' . print_r($result, true), LOGGER_DEBUG); + } + } + } + + /** + * @brief Checks if a child exists. + * + * @param string $name + * @return boolean + */ + public function childExists($name) { + // On /cloud we show a list of available channels. + // @todo what happens if no channels are available? + if ($this->red_path === '/' && $name === 'cloud') { + logger('RedDirectory::childExists() /cloud: true', LOGGER_DATA); + return true; + } + + $x = RedFileData($this->ext_path . '/' . $name, $this->auth, true); + logger('RedFileData returns: ' . print_r($x, true), LOGGER_DATA); + if ($x) + return true; + return false; + } + + /** + * @todo add description of what this function does. + * + * @throw DAV\Exception\NotFound + * @return void + */ + function getDir() { + logger('RedDirectory::getDir(): ' . $this->ext_path, LOGGER_DEBUG); + $this->auth->log(); + + $file = $this->ext_path; + + $x = strpos($file, '/cloud'); + if ($x === false) + return; + if ($x === 0) { + $file = substr($file, 6); + } + + if ((! $file) || ($file === '/')) { + return; + } + + $file = trim($file, '/'); + $path_arr = explode('/', $file); + + if (! $path_arr) + return; + + logger('RedDirectory::getDir(): path: ' . print_r($path_arr, true), LOGGER_DATA); + + $channel_name = $path_arr[0]; + + $r = q("SELECT channel_id FROM channel WHERE channel_address = '%s' AND NOT ( channel_pageflags & %d ) LIMIT 1", + dbesc($channel_name), + intval(PAGE_REMOVED) + ); + + if (! $r) { + throw new DAV\Exception\NotFound('The file with name: ' . $channel_name . ' could not be found.'); + return; + } + + $channel_id = $r[0]['channel_id']; + $this->auth->owner_id = $channel_id; + $this->auth->owner_nick = $channel_name; + + $path = '/' . $channel_name; + $folder = ''; + $os_path = ''; + + for ($x = 1; $x < count($path_arr); $x++) { + $r = q("select id, hash, filename, flags from attach where folder = '%s' and filename = '%s' and uid = %d and (flags & %d)", + dbesc($folder), + dbesc($path_arr[$x]), + intval($channel_id), + intval(ATTACH_FLAG_DIR) + ); + + if ($r && ( $r[0]['flags'] & ATTACH_FLAG_DIR)) { + $folder = $r[0]['hash']; + if (strlen($os_path)) + $os_path .= '/'; + $os_path .= $folder; + + $path = $path . '/' . $r[0]['filename']; + } + } + $this->folder_hash = $folder; + $this->os_path = $os_path; + return; + } + + /** + * @brief Returns the last modification time for the directory, as a UNIX + * timestamp. + * + * It looks for the last edited file in the folder. If it is an empty folder + * it returns the lastmodified time of the folder itself, to prevent zero + * timestamps. + * + * @return int last modification time in UNIX timestamp + */ + public function getLastModified() { + $r = q("SELECT edited FROM attach WHERE folder = '%s' AND uid = %d ORDER BY edited DESC LIMIT 1", + dbesc($this->folder_hash), + intval($this->auth->owner_id) + ); + if (! $r) { + $r = q("SELECT edited FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1", + dbesc($this->folder_hash), + intval($this->auth->owner_id) + ); + if (! $r) + return ''; + } + return datetime_convert('UTC', 'UTC', $r[0]['edited'], 'U'); + } + + /** + * @brief Return quota usage. + * + * Do guests relly see the used/free values from filesystem of the complete store directory? + * + * @return array with used and free values in bytes. + */ + public function getQuotaInfo() { + // values from the filesystem of the complete store/ directory + $limit = disk_total_space('store'); + $free = disk_free_space('store'); + + if ($this->auth->owner_id) { + $c = q("select * from channel where channel_id = %d and not (channel_pageflags & %d) limit 1", + intval($this->auth->owner_id), + intval(PAGE_REMOVED) + ); + + $ulimit = service_class_fetch($c[0]['channel_id'], 'attach_upload_limit'); + $limit = (($ulimit) ? $ulimit : $limit); + + $x = q("select sum(filesize) as total from attach where aid = %d", + intval($c[0]['channel_account_id']) + ); + $free = (($x) ? $limit - $x[0]['total'] : 0); + } + + return array( + $limit - $free, + $free + ); + } +} \ No newline at end of file diff --git a/include/RedDAV/RedFile.php b/include/RedDAV/RedFile.php new file mode 100644 index 000000000..32dbc17e5 --- /dev/null +++ b/include/RedDAV/RedFile.php @@ -0,0 +1,275 @@ +name = $name; + $this->data = $data; + $this->auth = $auth; + + logger('RedFile::__construct(): ' . print_r($this->data, true), LOGGER_DATA); + } + + /** + * @brief Returns the name of the file. + * + * @return string + */ + public function getName() { + logger('RedFile::getName(): ' . basename($this->name), LOGGER_DEBUG); + return basename($this->name); + } + + /** + * @brief Renames the file. + * + * @throw Sabre\DAV\Exception\Forbidden + * @param string $name The new name of the file. + * @return void + */ + public function setName($newName) { + logger('RedFile::setName(): ' . basename($this->name) . ' -> ' . $newName, LOGGER_DEBUG); + + if ((! $newName) || (! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) { + throw new DAV\Exception\Forbidden('Permission denied.'); + } + + $newName = str_replace('/', '%2F', $newName); + + $r = q("UPDATE attach SET filename = '%s' WHERE hash = '%s' AND id = %d LIMIT 1", + dbesc($this->data['filename']), + intval($this->data['id']) + ); + } + + /** + * @brief Updates the data of the file. + * + * @param resource $data + * @return void + */ + public function put($data) { + logger('RedFile::put(): ' . basename($this->name), LOGGER_DEBUG); + $size = 0; + + // @todo only 3 values are needed + $c = q("SELECT * FROM channel WHERE channel_id = %d AND NOT (channel_pageflags & %d) LIMIT 1", + intval($this->auth->owner_id), + intval(PAGE_REMOVED) + ); + + $r = q("SELECT flags, folder, data FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1", + dbesc($this->data['hash']), + intval($c[0]['channel_id']) + ); + if ($r) { + if ($r[0]['flags'] & ATTACH_FLAG_OS) { + $f = 'store/' . $this->auth->owner_nick . '/' . (($r[0]['data']) ? $r[0]['data'] : ''); + // @todo check return value and set $size directly + @file_put_contents($f, $data); + $size = @filesize($f); + logger('RedFile::put(): filename: ' . $f . ' size: ' . $size, LOGGER_DEBUG); + } else { + $r = q("UPDATE attach SET data = '%s' WHERE hash = '%s' AND uid = %d LIMIT 1", + dbesc(stream_get_contents($data)), + dbesc($this->data['hash']), + intval($this->data['uid']) + ); + $r = q("SELECT length(data) AS fsize FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1", + dbesc($this->data['hash']), + intval($this->data['uid']) + ); + if ($r) { + $size = $r[0]['fsize']; + } + } + } + + // returns now() + $edited = datetime_convert(); + + $d = q("UPDATE attach SET filesize = '%s', edited = '%s' WHERE hash = '%s' AND uid = %d LIMIT 1", + dbesc($size), + dbesc($edited), + dbesc($this->data['hash']), + intval($c[0]['channel_id']) + ); + + // update the folder's lastmodified timestamp + $e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d LIMIT 1", + dbesc($edited), + dbesc($r[0]['folder']), + intval($c[0]['channel_id']) + ); + + // @todo do we really want to remove the whole file if an update fails + // because of maxfilesize or quota? + // There is an Exception "InsufficientStorage" or "PaymentRequired" for + // our service class from SabreDAV we could use. + + $maxfilesize = get_config('system', 'maxfilesize'); + if (($maxfilesize) && ($size > $maxfilesize)) { + attach_delete($c[0]['channel_id'], $this->data['hash']); + return; + } + + $limit = service_class_fetch($c[0]['channel_id'], 'attach_upload_limit'); + if ($limit !== false) { + $x = q("select sum(filesize) as total from attach where aid = %d ", + intval($c[0]['channel_account_id']) + ); + if (($x) && ($x[0]['total'] + $size > $limit)) { + logger('RedFile::put(): service class limit exceeded for ' . $c[0]['channel_name'] . ' total usage is ' . $x[0]['total'] . ' limit is ' . $limit); + attach_delete($c[0]['channel_id'], $this->data['hash']); + return; + } + } + } + + /** + * @brief Returns the raw data. + * + * @return string + */ + public function get() { + logger('RedFile::get(): ' . basename($this->name), LOGGER_DEBUG); + + $r = q("SELECT data, flags, filename, filetype FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1", + dbesc($this->data['hash']), + intval($this->data['uid']) + ); + if ($r) { + // @todo this should be a global definition + $unsafe_types = array('text/html', 'text/css', 'application/javascript'); + + if (in_array($r[0]['filetype'], $unsafe_types)) { + header('Content-disposition: attachment; filename="' . $r[0]['filename'] . '"'); + header('Content-type: text/plain'); + } + + if ($r[0]['flags'] & ATTACH_FLAG_OS ) { + $f = 'store/' . $this->auth->owner_nick . '/' . (($this->os_path) ? $this->os_path . '/' : '') . $r[0]['data']; + return fopen($f, 'rb'); + } + return $r[0]['data']; + } + } + + /** + * @brief Returns the ETag for a file. + * + * An ETag is a unique identifier representing the current version of the file. + * If the file changes, the ETag MUST change. + * The ETag is an arbitrary string, but MUST be surrounded by double-quotes. + * + * Return null if the ETag can not effectively be determined. + * + * @return mixed + */ + public function getETag() { + $ret = null; + if ($this->data['hash']) { + $ret = '"' . $this->data['hash'] . '"'; + } + return $ret; + } + + /** + * @brief Returns the mime-type for a file. + * + * If null is returned, we'll assume application/octet-stream + * + * @return mixed + */ + public function getContentType() { + // @todo this should be a global definition. + $unsafe_types = array('text/html', 'text/css', 'application/javascript'); + if (in_array($this->data['filetype'], $unsafe_types)) { + return 'text/plain'; + } + return $this->data['filetype']; + } + + /** + * @brief Returns the size of the node, in bytes. + * + * @return int + */ + public function getSize() { + return $this->data['filesize']; + } + + /** + * @brief Returns the last modification time for the file, as a unix + * timestamp. + * + * @return int last modification time in UNIX timestamp + */ + public function getLastModified() { + return datetime_convert('UTC', 'UTC', $this->data['edited'], 'U'); + } + + /** + * @brief Delete the file. + * + * @throw Sabre\DAV\Exception\Forbidden + * @return void + */ + public function delete() { + logger('RedFile::delete(): ' . basename($this->name), LOGGER_DEBUG); + + if ((! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) { + throw new DAV\Exception\Forbidden('Permission denied.'); + } + + if ($this->auth->owner_id !== $this->auth->channel_id) { + if (($this->auth->observer !== $this->data['creator']) || ($this->data['flags'] & ATTACH_FLAG_DIR)) { + throw new DAV\Exception\Forbidden('Permission denied.'); + } + } + + attach_delete($this->auth->owner_id, $this->data['hash']); + } +} \ No newline at end of file diff --git a/include/reddav.php b/include/reddav.php index 5c93daf1f..6785131c6 100644 --- a/include/reddav.php +++ b/include/reddav.php @@ -1,724 +1,31 @@ = 2.0 * requires PHP >= 5.4. * * @todo split up the classes into own files. + * + * @link http://github.com/friendica/red + * @license http://opensource.org/licenses/mit-license.php The MIT License (MIT) */ use Sabre\DAV; +use RedMatrix\RedDAV; require_once('vendor/autoload.php'); require_once('include/attach.php'); - -/** - * @brief RedDirectory class. - * - * A class that represents a directory. - * - * @extends \Sabre\DAV\Node - * @implements \Sabre\DAV\ICollection - * @implements \Sabre\DAV\IQuota - */ -class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { - - /** - * @brief The path inside /cloud - * - * @var string - */ - private $red_path; - private $folder_hash; - /** - * @brief The full path as seen in the browser. - * /cloud + $red_path - * @todo I think this is not used anywhere, we always strip '/cloud' and only use it in debug - * @var string - */ - private $ext_path; - private $root_dir = ''; - private $auth; - /** - * @brief The real path on the filesystem. - * The actual path in store/ with the hashed names. - * - * @var string - */ - private $os_path = ''; - - /** - * @brief Sets up the directory node, expects a full path. - * - * @param string $ext_path a full path - * @param RedBasicAuth &$auth_plugin - */ - public function __construct($ext_path, &$auth_plugin) { - logger('RedDirectory::__construct() ' . $ext_path, LOGGER_DATA); - $this->ext_path = $ext_path; - // remove "/cloud" from the beginning of the path - $this->red_path = ((strpos($ext_path, '/cloud') === 0) ? substr($ext_path, 6) : $ext_path); - if (! $this->red_path) { - $this->red_path = '/'; - } - $this->auth = $auth_plugin; - $this->folder_hash = ''; - $this->getDir(); - - if ($this->auth->browser) { - $this->auth->browser->set_writeable(); - } - } - - private function log() { - logger('RedDirectory::log() ext_path ' . $this->ext_path, LOGGER_DATA); - logger('RedDirectory::log() os_path ' . $this->os_path, LOGGER_DATA); - logger('RedDirectory::log() red_path ' . $this->red_path, LOGGER_DATA); - } - - /** - * @brief Returns an array with all the child nodes. - * - * @throws DAV\Exception\Forbidden - * @return array DAV\INode[] - */ - public function getChildren() { - logger('RedDirectory::getChildren() called for ' . $this->ext_path, LOGGER_DATA); - $this->log(); - - if (get_config('system', 'block_public') && (! $this->auth->channel_id) && (! $this->auth->observer)) { - throw new DAV\Exception\Forbidden('Permission denied.'); - } - - if (($this->auth->owner_id) && (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'view_storage'))) { - throw new DAV\Exception\Forbidden('Permission denied.'); - } - - $contents = RedCollectionData($this->red_path, $this->auth); - return $contents; - } - - /** - * @brief Returns a child by name. - * - * - * @throw DAV\Exception\Forbidden - * @throw DAV\Exception\NotFound - * @param string $name - */ - public function getChild($name) { - logger('RedDirectory::getChild(): ' . $name, LOGGER_DATA); - - if (get_config('system', 'block_public') && (! $this->auth->channel_id) && (! $this->auth->observer)) { - throw new DAV\Exception\Forbidden('Permission denied.'); - } - - if (($this->auth->owner_id) && (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'view_storage'))) { - throw new DAV\Exception\Forbidden('Permission denied.'); - } - - if ($this->red_path === '/' && $name === 'cloud') { - return new RedDirectory('/cloud', $this->auth); - } - - $x = RedFileData($this->ext_path . '/' . $name, $this->auth); - if ($x) { - return $x; - } - - throw new DAV\Exception\NotFound('The file with name: ' . $name . ' could not be found.'); - } - - /** - * @brief Returns the name of the directory. - * - * @return string - */ - public function getName() { - logger('RedDirectory::getName() returns: ' . basename($this->red_path), LOGGER_DATA); - return (basename($this->red_path)); - } - - /** - * @brief Renames the directory. - * - * @todo handle duplicate directory name - * - * @throw DAV\Exception\Forbidden - * @param string $name The new name of the directory. - * @return void - */ - public function setName($name) { - logger('RedDirectory::setName(): ' . basename($this->red_path) . ' -> ' . $name, LOGGER_DATA); - - if ((! $name) || (! $this->auth->owner_id)) { - logger('RedDirectory::setName(): permission denied'); - throw new DAV\Exception\Forbidden('Permission denied.'); - } - - if (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage')) { - logger('RedDirectory::setName(): permission denied'); - throw new DAV\Exception\Forbidden('Permission denied.'); - } - - list($parent_path, ) = DAV\URLUtil::splitPath($this->red_path); - $new_path = $parent_path . '/' . $name; - - $r = q("UPDATE attach SET filename = '%s' WHERE hash = '%s' AND uid = %d LIMIT 1", - dbesc($name), - dbesc($this->folder_hash), - intval($this->auth->owner_id) - ); - - $this->red_path = $new_path; - } - - /** - * @brief Creates a new file in the directory. - * - * Data will either be supplied as a stream resource, or in certain cases - * as a string. Keep in mind that you may have to support either. - * - * After successful creation of the file, you may choose to return the ETag - * of the new file here. - * - * @throws DAV\Exception\Forbidden - * @param string $name Name of the file - * @param resource|string $data Initial payload - * @return null|string ETag - */ - public function createFile($name, $data = null) { - logger('RedDirectory::createFile(): ' . $name, LOGGER_DATA); - - if (! $this->auth->owner_id) { - logger('RedDirectory::createFile(): permission denied'); - throw new DAV\Exception\Forbidden('Permission denied.'); - } - - if (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage')) { - logger('RedDirectory::createFile(): permission denied'); - throw new DAV\Exception\Forbidden('Permission denied.'); - } - - $mimetype = z_mime_content_type($name); - - $c = q("SELECT * FROM channel WHERE channel_id = %d AND NOT (channel_pageflags & %d) LIMIT 1", - intval($this->auth->owner_id), - intval(PAGE_REMOVED) - ); - - if (! $c) { - logger('RedDirectory::createFile(): no channel'); - throw new DAV\Exception\Forbidden('Permission denied.'); - } - - $filesize = 0; - $hash = random_string(); - - $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, folder, flags, filetype, filesize, revision, data, created, edited, allow_cid, allow_gid, deny_cid, deny_gid ) - VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", - intval($c[0]['channel_account_id']), - intval($c[0]['channel_id']), - dbesc($hash), - dbesc($this->auth->observer), - dbesc($name), - dbesc($this->folder_hash), - dbesc(ATTACH_FLAG_OS), - dbesc($mimetype), - intval($filesize), - intval(0), - dbesc($this->os_path . '/' . $hash), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc($c[0]['channel_allow_cid']), - dbesc($c[0]['channel_allow_gid']), - dbesc($c[0]['channel_deny_cid']), - dbesc($c[0]['channel_deny_gid']) - ); - - $f = 'store/' . $this->auth->owner_nick . '/' . (($this->os_path) ? $this->os_path . '/' : '') . $hash; - - // returns the number of bytes that were written to the file, or FALSE on failure - $size = file_put_contents($f, $data); - // delete attach entry if file_put_contents() failed - if ($size === false) { - logger('RedDirectory::createFile(): file_put_contents() failed for ' . $name, LOGGER_DEBUG); - attach_delete($c[0]['channel_id'], $hash); - return; - } - - // returns now - $edited = datetime_convert(); - - // updates entry with filesize and timestamp - $d = q("UPDATE attach SET filesize = '%s', edited = '%s' WHERE hash = '%s' AND uid = %d LIMIT 1", - dbesc($size), - dbesc($edited), - dbesc($hash), - intval($c[0]['channel_id']) - ); - - // update the folder's lastmodified timestamp - $e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d LIMIT 1", - dbesc($edited), - dbesc($this->folder_hash), - intval($c[0]['channel_id']) - ); - - $maxfilesize = get_config('system', 'maxfilesize'); - if (($maxfilesize) && ($size > $maxfilesize)) { - attach_delete($c[0]['channel_id'], $hash); - return; - } - - // check against service class quota - $limit = service_class_fetch($c[0]['channel_id'], 'attach_upload_limit'); - if ($limit !== false) { - $x = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d ", - intval($c[0]['channel_account_id']) - ); - if (($x) && ($x[0]['total'] + $size > $limit)) { - logger('reddav: service class limit exceeded for ' . $c[0]['channel_name'] . ' total usage is ' . $x[0]['total'] . ' limit is ' . $limit); - attach_delete($c[0]['channel_id'], $hash); - return; - } - } - } - - /** - * @brief Creates a new subdirectory. - * - * @param string $name the directory to create - * @return void - */ - public function createDirectory($name) { - logger('RedDirectory::createDirectory(): ' . $name, LOGGER_DEBUG); - - if ((! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) { - throw new DAV\Exception\Forbidden('Permission denied.'); - } - - $r = q("SELECT * FROM channel WHERE channel_id = %d AND NOT (channel_pageflags & %d) LIMIT 1", - intval($this->auth->owner_id), - intval(PAGE_REMOVED) - ); - - if ($r) { - $result = attach_mkdir($r[0], $this->auth->observer, array('filename' => $name, 'folder' => $this->folder_hash)); - if (! $result['success']) { - logger('RedDirectory::createDirectory(): ' . print_r($result, true), LOGGER_DEBUG); - } - } - } - - /** - * @brief Checks if a child exists. - * - * @param string $name - * @return boolean - */ - public function childExists($name) { - // On /cloud we show a list of available channels. - // @todo what happens if no channels are available? - if ($this->red_path === '/' && $name === 'cloud') { - logger('RedDirectory::childExists() /cloud: true', LOGGER_DATA); - return true; - } - - $x = RedFileData($this->ext_path . '/' . $name, $this->auth, true); - logger('RedFileData returns: ' . print_r($x, true), LOGGER_DATA); - if ($x) - return true; - return false; - } - - /** - * @todo add description of what this function does. - * - * @throw DAV\Exception\NotFound - * @return void - */ - function getDir() { - logger('RedDirectory::getDir(): ' . $this->ext_path, LOGGER_DEBUG); - $this->auth->log(); - - $file = $this->ext_path; - - $x = strpos($file, '/cloud'); - if ($x === false) - return; - if ($x === 0) { - $file = substr($file, 6); - } - - if ((! $file) || ($file === '/')) { - return; - } - - $file = trim($file, '/'); - $path_arr = explode('/', $file); - - if (! $path_arr) - return; - - logger('RedDirectory::getDir(): path: ' . print_r($path_arr, true), LOGGER_DATA); - - $channel_name = $path_arr[0]; - - $r = q("SELECT channel_id FROM channel WHERE channel_address = '%s' AND NOT ( channel_pageflags & %d ) LIMIT 1", - dbesc($channel_name), - intval(PAGE_REMOVED) - ); - - if (! $r) { - throw new DAV\Exception\NotFound('The file with name: ' . $channel_name . ' could not be found.'); - return; - } - - $channel_id = $r[0]['channel_id']; - $this->auth->owner_id = $channel_id; - $this->auth->owner_nick = $channel_name; - - $path = '/' . $channel_name; - $folder = ''; - $os_path = ''; - - for ($x = 1; $x < count($path_arr); $x++) { - $r = q("select id, hash, filename, flags from attach where folder = '%s' and filename = '%s' and uid = %d and (flags & %d)", - dbesc($folder), - dbesc($path_arr[$x]), - intval($channel_id), - intval(ATTACH_FLAG_DIR) - ); - - if ($r && ( $r[0]['flags'] & ATTACH_FLAG_DIR)) { - $folder = $r[0]['hash']; - if (strlen($os_path)) - $os_path .= '/'; - $os_path .= $folder; - - $path = $path . '/' . $r[0]['filename']; - } - } - $this->folder_hash = $folder; - $this->os_path = $os_path; - return; - } - - /** - * @brief Returns the last modification time for the directory, as a UNIX - * timestamp. - * - * It looks for the last edited file in the folder. If it is an empty folder - * it returns the lastmodified time of the folder itself, to prevent zero - * timestamps. - * - * @return int last modification time in UNIX timestamp - */ - public function getLastModified() { - $r = q("SELECT edited FROM attach WHERE folder = '%s' AND uid = %d ORDER BY edited DESC LIMIT 1", - dbesc($this->folder_hash), - intval($this->auth->owner_id) - ); - if (! $r) { - $r = q("SELECT edited FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1", - dbesc($this->folder_hash), - intval($this->auth->owner_id) - ); - if (! $r) - return ''; - } - return datetime_convert('UTC', 'UTC', $r[0]['edited'], 'U'); - } - - /** - * @brief Return quota usage. - * - * Do guests relly see the used/free values from filesystem of the complete store directory? - * - * @return array with used and free values in bytes. - */ - public function getQuotaInfo() { - // values from the filesystem of the complete store/ directory - $limit = disk_total_space('store'); - $free = disk_free_space('store'); - - if ($this->auth->owner_id) { - $c = q("select * from channel where channel_id = %d and not (channel_pageflags & %d) limit 1", - intval($this->auth->owner_id), - intval(PAGE_REMOVED) - ); - - $ulimit = service_class_fetch($c[0]['channel_id'], 'attach_upload_limit'); - $limit = (($ulimit) ? $ulimit : $limit); - - $x = q("select sum(filesize) as total from attach where aid = %d", - intval($c[0]['channel_account_id']) - ); - $free = (($x) ? $limit - $x[0]['total'] : 0); - } - - return array( - $limit - $free, - $free - ); - } -} // class RedDirectory - - - -/** - * RedFile class. - * - */ -class RedFile extends DAV\Node implements DAV\IFile { - - private $data; - private $auth; - private $name; - - /** - * Sets up the node, expects a full path name. - * - * @param string $name - * @param array $data from attach table - * @param &$auth - */ - public function __construct($name, $data, &$auth) { - $this->name = $name; - $this->data = $data; - $this->auth = $auth; - - logger('RedFile::__construct(): ' . print_r($this->data, true), LOGGER_DATA); - } - - /** - * @brief Returns the name of the file. - * - * @return string - */ - public function getName() { - logger('RedFile::getName(): ' . basename($this->name), LOGGER_DEBUG); - return basename($this->name); - } - - /** - * @brief Renames the file. - * - * @throw DAV\Exception\Forbidden - * @param string $name The new name of the file. - * @return void - */ - public function setName($newName) { - logger('RedFile::setName(): ' . basename($this->name) . ' -> ' . $newName, LOGGER_DEBUG); - - if ((! $newName) || (! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) { - throw new DAV\Exception\Forbidden('Permission denied.'); - } - - $newName = str_replace('/', '%2F', $newName); - - $r = q("UPDATE attach SET filename = '%s' WHERE hash = '%s' AND id = %d LIMIT 1", - dbesc($this->data['filename']), - intval($this->data['id']) - ); - } - - /** - * @brief Updates the data of the file. - * - * @param resource $data - * @return void - */ - public function put($data) { - logger('RedFile::put(): ' . basename($this->name), LOGGER_DEBUG); - $size = 0; - - // @todo only 3 values are needed - $c = q("SELECT * FROM channel WHERE channel_id = %d AND NOT (channel_pageflags & %d) LIMIT 1", - intval($this->auth->owner_id), - intval(PAGE_REMOVED) - ); - - $r = q("SELECT flags, folder, data FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1", - dbesc($this->data['hash']), - intval($c[0]['channel_id']) - ); - if ($r) { - if ($r[0]['flags'] & ATTACH_FLAG_OS) { - $f = 'store/' . $this->auth->owner_nick . '/' . (($r[0]['data']) ? $r[0]['data'] : ''); - // @todo check return value and set $size directly - @file_put_contents($f, $data); - $size = @filesize($f); - logger('RedFile::put(): filename: ' . $f . ' size: ' . $size, LOGGER_DEBUG); - } else { - $r = q("UPDATE attach SET data = '%s' WHERE hash = '%s' AND uid = %d LIMIT 1", - dbesc(stream_get_contents($data)), - dbesc($this->data['hash']), - intval($this->data['uid']) - ); - $r = q("SELECT length(data) AS fsize FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1", - dbesc($this->data['hash']), - intval($this->data['uid']) - ); - if ($r) { - $size = $r[0]['fsize']; - } - } - } - - // returns now() - $edited = datetime_convert(); - - $d = q("UPDATE attach SET filesize = '%s', edited = '%s' WHERE hash = '%s' AND uid = %d LIMIT 1", - dbesc($size), - dbesc($edited), - dbesc($this->data['hash']), - intval($c[0]['channel_id']) - ); - - // update the folder's lastmodified timestamp - $e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d LIMIT 1", - dbesc($edited), - dbesc($r[0]['folder']), - intval($c[0]['channel_id']) - ); - - // @todo do we really want to remove the whole file if an update fails - // because of maxfilesize or quota? - // There is an Exception "InsufficientStorage" or "PaymentRequired" for - // our service class from SabreDAV we could use. - - $maxfilesize = get_config('system', 'maxfilesize'); - if (($maxfilesize) && ($size > $maxfilesize)) { - attach_delete($c[0]['channel_id'], $this->data['hash']); - return; - } - - $limit = service_class_fetch($c[0]['channel_id'], 'attach_upload_limit'); - if ($limit !== false) { - $x = q("select sum(filesize) as total from attach where aid = %d ", - intval($c[0]['channel_account_id']) - ); - if (($x) && ($x[0]['total'] + $size > $limit)) { - logger('RedFile::put(): service class limit exceeded for ' . $c[0]['channel_name'] . ' total usage is ' . $x[0]['total'] . ' limit is ' . $limit); - attach_delete($c[0]['channel_id'], $this->data['hash']); - return; - } - } - } - - /** - * @brief Returns the raw data. - * - * @return string - */ - public function get() { - logger('RedFile::get(): ' . basename($this->name), LOGGER_DEBUG); - - $r = q("select data, flags, filename, filetype from attach where hash = '%s' and uid = %d limit 1", - dbesc($this->data['hash']), - intval($this->data['uid']) - ); - if ($r) { - // @todo this should be a global definition - $unsafe_types = array('text/html', 'text/css', 'application/javascript'); - - if (in_array($r[0]['filetype'], $unsafe_types)) { - header('Content-disposition: attachment; filename="' . $r[0]['filename'] . '"'); - header('Content-type: text/plain'); - } - - if ($r[0]['flags'] & ATTACH_FLAG_OS ) { - $f = 'store/' . $this->auth->owner_nick . '/' . (($this->os_path) ? $this->os_path . '/' : '') . $r[0]['data']; - return fopen($f, 'rb'); - } - return $r[0]['data']; - } - } - - /** - * @brief Returns the ETag for a file. - * - * An ETag is a unique identifier representing the current version of the file. If the file changes, the ETag MUST change. - * The ETag is an arbitrary string, but MUST be surrounded by double-quotes. - * - * Return null if the ETag can not effectively be determined. - * - * @return mixed - */ - public function getETag() { - $ret = null; - if ($this->data['hash']) { - $ret = '"' . $this->data['hash'] . '"'; - } - return $ret; - } - - /** - * @brief Returns the mime-type for a file. - * - * If null is returned, we'll assume application/octet-stream - * - * @return mixed - */ - public function getContentType() { - // @todo this should be a global definition. - $unsafe_types = array('text/html', 'text/css', 'application/javascript'); - if (in_array($this->data['filetype'], $unsafe_types)) { - return 'text/plain'; - } - return $this->data['filetype']; - } - - /** - * @brief Returns the size of the node, in bytes. - * - * @return int - */ - public function getSize() { - return $this->data['filesize']; - } - - /** - * @brief Returns the last modification time for the file, as a unix - * timestamp. - * - * @return int last modification time in UNIX timestamp - */ - public function getLastModified() { - return datetime_convert('UTC', 'UTC', $this->data['edited'], 'U'); - } - - /** - * @brief Delete the file. - * - * @throw DAV\Exception\Forbidden - * @return void - */ - public function delete() { - logger('RedFile::delete(): ' . basename($this->name), LOGGER_DEBUG); - - if ((! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) { - throw new DAV\Exception\Forbidden('Permission denied.'); - } - - if ($this->auth->owner_id !== $this->auth->channel_id) { - if (($this->auth->observer !== $this->data['creator']) || ($this->data['flags'] & ATTACH_FLAG_DIR)) { - throw new DAV\Exception\Forbidden('Permission denied.'); - } - } - - attach_delete($this->auth->owner_id, $this->data['hash']); - } -} // class RedFile - +require_once('include/RedDAV/RedFile.php'); +require_once('include/RedDAV/RedDirectory.php'); +require_once('include/RedDAV/RedBasicAuth.php'); /** * @brief Returns an array with viewable channels. @@ -727,6 +34,7 @@ class RedFile extends DAV\Node implements DAV\IFile { * has view_storage perms. * * @todo Is there any reason why this is not inside RedDirectory class? + * @fixme function name looks like a class name, should we rename it? * * @param $auth * @return array containing RedDirectory objects @@ -744,7 +52,7 @@ function RedChannelList(&$auth) { if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage')) { logger('RedChannelList: ' . '/cloud/' . $rr['channel_address'], LOGGER_DATA); // @todo can't we drop '/cloud'? It gets stripped off anyway in RedDirectory - $ret[] = new RedDirectory('/cloud/' . $rr['channel_address'], $auth); + $ret[] = new RedDAV\RedDirectory('/cloud/' . $rr['channel_address'], $auth); } } } @@ -757,7 +65,9 @@ function RedChannelList(&$auth) { * * Array with all RedDirectory and RedFile DAV\Node items for the given path. * - * @todo Is there any reason why this is not inside RedDirectory class? Seems only to be used there and we could simplify it a bit there. + * @todo Is there any reason why this is not inside RedDirectory class? Seems + * only to be used there and we could simplify it a bit there. + * @fixme function name looks like a class name, should we rename it? * * @param string $file path to a directory * @param &$auth @@ -854,9 +164,9 @@ function RedCollectionData($file, &$auth) { if ($rr['flags'] & ATTACH_FLAG_DIR) { // @todo can't we drop '/cloud'? it gets stripped off anyway in RedDirectory - $ret[] = new RedDirectory('/cloud' . $path . '/' . $rr['filename'], $auth); + $ret[] = new RedDAV\RedDirectory('/cloud' . $path . '/' . $rr['filename'], $auth); } else { - $ret[] = new RedFile('/cloud' . $path . '/' . $rr['filename'], $rr, $auth); + $ret[] = new RedDAV\RedFile('/cloud' . $path . '/' . $rr['filename'], $rr, $auth); } } @@ -867,6 +177,8 @@ function RedCollectionData($file, &$auth) { /** * @brief TODO What exactly is this function for? * + * @fixme function name looks like a class name, should we rename it? + * * @param string $file * @param &$auth * @param boolean $test (optional) enable test mode @@ -880,7 +192,7 @@ function RedFileData($file, &$auth, $test = false) { } if ((! $file) || ($file === '/')) { - return new RedDirectory('/', $auth); + return new RedDAV\RedDirectory('/', $auth); } $file = trim($file, '/'); @@ -951,7 +263,7 @@ function RedFileData($file, &$auth, $test = false) { if ($test) return true; // final component was a directory. - return new RedDirectory('/cloud/' . $file, $auth); + return new RedDAV\RedDirectory('/cloud/' . $file, $auth); } if ($errors) { @@ -971,212 +283,10 @@ function RedFileData($file, &$auth, $test = false) { if ($r[0]['flags'] & ATTACH_FLAG_DIR) { // @todo can't we drop '/cloud'? it gets stripped off anyway in RedDirectory - return new RedDirectory('/cloud' . $path . '/' . $r[0]['filename'], $auth); + return new RedDAV\RedDirectory('/cloud' . $path . '/' . $r[0]['filename'], $auth); } else { - return new RedFile('/cloud' . $path . '/' . $r[0]['filename'], $r[0], $auth); + return new RedDAV\RedFile('/cloud' . $path . '/' . $r[0]['filename'], $r[0], $auth); } } return false; -} - - - -/** - * @brief Authentication backend class for RedDAV. - * - * This class also contains some data which is not necessary for authentication - * like timezone settings. - * - */ -class RedBasicAuth extends DAV\Auth\Backend\AbstractBasic { - - /** - * @brief This variable holds the currently logged-in channel_address. - * - * It is used for building path in filestorage/. - * - * @var string|null - */ - protected $channel_name = null; - /** - * channel_id of the current channel of the logged-in account. - * - * @var int - */ - public $channel_id = 0; - /** - * channel_hash of the current channel of the logged-in account. - * - * @var string - */ - public $channel_hash = ''; - /** - * Set in mod/cloud.php to observer_hash. - * - * @var string - */ - public $observer = ''; - /** - * - * @see RedBrowser::set_writeable() - * @var DAV\Browser\Plugin - */ - public $browser; - /** - * channel_id of the current visited path. Set in RedDirectory::getDir(). - * - * @var int - */ - public $owner_id = 0; - /** - * channel_name of the current visited path. Set in RedDirectory::getDir(). - * - * Used for creating the path in cloud/ - * - * @var string - */ - public $owner_nick = ''; - /** - * Timezone from the visiting channel's channel_timezone. - * - * Used in @ref RedBrowser - * - * @var string - */ - protected $timezone = ''; - - - /** - * @brief Validates a username and password. - * - * Guest access is granted with the password "+++". - * - * @see DAV\Auth\Backend\AbstractBasic::validateUserPass - * @param string $username - * @param string $password - * @return bool - */ - protected function validateUserPass($username, $password) { - if (trim($password) === '+++') { - logger('(DAV): RedBasicAuth::validateUserPass(): guest ' . $username); - return true; - } - - require_once('include/auth.php'); - $record = account_verify_password($username, $password); - if ($record && $record['account_default_channel']) { - $r = q("SELECT * FROM channel WHERE channel_account_id = %d AND channel_id = %d LIMIT 1", - intval($record['account_id']), - intval($record['account_default_channel']) - ); - if ($r) { - return $this->setAuthenticated($r[0]); - } - } - $r = q("SELECT * FROM channel WHERE channel_address = '%s' LIMIT 1", - dbesc($username) - ); - if ($r) { - $x = q("SELECT account_flags, account_salt, account_password FROM account WHERE account_id = %d LIMIT 1", - intval($r[0]['channel_account_id']) - ); - if ($x) { - // @fixme this foreach should not be needed? - foreach ($x as $record) { - if (($record['account_flags'] == ACCOUNT_OK) || ($record['account_flags'] == ACCOUNT_UNVERIFIED) - && (hash('whirlpool', $record['account_salt'] . $password) === $record['account_password'])) { - logger('(DAV) RedBasicAuth: password verified for ' . $username); - return $this->setAuthenticated($r[0]); - } - } - } - } - logger('(DAV) RedBasicAuth: password failed for ' . $username); - return false; - } - - /** - * @brief Sets variables and session parameters after successfull authentication. - * - * @param array $r - * Array with the values for the authenticated channel. - * @return bool - */ - protected function setAuthenticated($r) { - $this->channel_name = $r['channel_address']; - $this->channel_id = $r['channel_id']; - $this->channel_hash = $this->observer = $r['channel_hash']; - $_SESSION['uid'] = $r['channel_id']; - $_SESSION['account_id'] = $r['channel_account_id']; - $_SESSION['authenticated'] = true; - return true; - } - - /** - * Sets the channel_name from the currently logged-in channel. - * - * @param string $name - * The channel's name - */ - public function setCurrentUser($name) { - $this->channel_name = $name; - } - /** - * Returns information about the currently logged-in channel. - * - * If nobody is currently logged in, this method should return null. - * - * @see DAV\Auth\Backend\AbstractBasic::getCurrentUser - * @return string|null - */ - public function getCurrentUser() { - return $this->channel_name; - } - - /** - * @brief Sets the timezone from the channel in RedBasicAuth. - * - * Set in mod/cloud.php if the channel has a timezone set. - * - * @param string $timezone - * The channel's timezone. - * @return void - */ - public function setTimezone($timezone) { - $this->timezone = $timezone; - } - /** - * @brief Returns the timezone. - * - * @return string - * Return the channel's timezone. - */ - public function getTimezone() { - return $this->timezone; - } - - /** - * @brief Set browser plugin for SabreDAV. - * - * @see RedBrowser::set_writeable() - * @param DAV\Browser\Plugin $browser - */ - public function setBrowserPlugin($browser) { - $this->browser = $browser; - } - - /** - * Prints out all RedBasicAuth variables to logger(). - * - * @return void - */ - public function log() { - logger('dav: auth: channel_name ' . $this->channel_name, LOGGER_DATA); - logger('dav: auth: channel_id ' . $this->channel_id, LOGGER_DATA); - logger('dav: auth: channel_hash ' . $this->channel_hash, LOGGER_DATA); - logger('dav: auth: observer ' . $this->observer, LOGGER_DATA); - logger('dav: auth: owner_id ' . $this->owner_id, LOGGER_DATA); - logger('dav: auth: owner_nick ' . $this->owner_nick, LOGGER_DATA); - } - -} // class RedBasicAuth +} \ No newline at end of file -- cgit v1.2.3 From 4bf758cc5b4b204fce0560af2fce719f37f2a9a3 Mon Sep 17 00:00:00 2001 From: friendica Date: Sun, 12 Oct 2014 01:40:48 -0700 Subject: content deletion issue --- include/items.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/items.php b/include/items.php index c4ae948b8..40343d505 100755 --- a/include/items.php +++ b/include/items.php @@ -3977,7 +3977,12 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL) { // send the notification upstream/downstream as the case may be // only send notifications to others if this is the owner's wall item. - if(($item['item_flags'] & ITEM_WALL) && ($stage != DROPITEM_PHASE2)) + // This isn't optimal. We somehow need to pass to this function whether or not + // to call the notifier, or we need to call the notifier from the calling function. + // We'll rely on the undocumented behaviour that DROPITEM_PHASE1 is (hopefully) only + // set if we know we're going to send delete notifications out to others. + + if((($item['item_flags'] & ITEM_WALL) && ($stage != DROPITEM_PHASE2)) || ($stage == DROPITEM_PHASE1)) proc_run('php','include/notifier.php','drop',$notify_id); goaway($a->get_baseurl() . '/' . $_SESSION['return_url']); -- cgit v1.2.3 From 718bea5d455dedb38c69ea696cc36066d78d8ef0 Mon Sep 17 00:00:00 2001 From: friendica Date: Sun, 12 Oct 2014 15:18:49 -0700 Subject: cleanup of sync_locations and better logging. There was one significant code change but it is unrelated to current issues, basically if no primary was set we were setting everything as primary. --- include/zot.php | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/zot.php b/include/zot.php index fda2a2bea..2d674c354 100644 --- a/include/zot.php +++ b/include/zot.php @@ -1716,7 +1716,7 @@ function process_location_delivery($sender,$arr,$deliveries) { $sender['key'] = $r[0]['xchan_pubkey']; $x = sync_locations($sender,$arr,true); - logger('process_location_delivery: results: ' . print_r($x,true), LOGGER_DATA); + logger('process_location_delivery: results: ' . print_r($x,true), LOGGER_DEBUG); } @@ -1740,6 +1740,11 @@ function sync_locations($sender,$arr,$absolute = false) { } } + // Ensure that they have one primary hub + + if(! $has_primary) + $arr['locations'][0]['primary'] = true; + foreach($arr['locations'] as $location) { if(! rsa_verify($location['url'],base64url_decode($location['url_sig']),$sender['key'])) { logger('sync_locations: Unable to verify site signature for ' . $location['url']); @@ -1747,10 +1752,6 @@ function sync_locations($sender,$arr,$absolute = false) { continue; } - // Ensure that they have one primary hub - - if(! $has_primary) - $location['primary'] = true; for($x = 0; $x < count($xisting); $x ++) { if(($xisting[$x]['hubloc_url'] === $location['url']) @@ -1824,6 +1825,8 @@ function sync_locations($sender,$arr,$absolute = false) { q("delete from hubloc where hubloc_id = %d limit 1", intval($r[$h]['hubloc_id']) ); + $what .= 'duplicate_hubloc_removed '; + $changed = true; } } @@ -1850,7 +1853,8 @@ function sync_locations($sender,$arr,$absolute = false) { continue; } - // new hub claiming to be primary. Make it so. + // Existing hubs are dealt with. Now let's process any new ones. + // New hub claiming to be primary. Make it so by removing any existing primaries. if(intval($location['primary'])) { $r = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_hash = '%s' and (hubloc_flags & %d )", @@ -1893,7 +1897,7 @@ function sync_locations($sender,$arr,$absolute = false) { dbesc(datetime_convert()), intval($x['hubloc_id']) ); - $what .= 'removed_hub'; + $what .= 'removed_hub '; $changed = true; } } -- cgit v1.2.3 From 41b74dd7ac2c879841873d59423be7d2577b6f87 Mon Sep 17 00:00:00 2001 From: friendica Date: Sun, 12 Oct 2014 21:20:08 -0700 Subject: diaspora_send_status() - recalculate markdown translation to pickup any later message changes after original submission like wall-to-wall attributions for instance. Normally this would've come from our cached version which was stored prior to tag_deliver being run and therefore isn't yet aware that wall-to-wall status may have changed after delivery. --- include/bb2diaspora.php | 4 ++-- include/diaspora.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php index a80b3343b..76708143b 100644 --- a/include/bb2diaspora.php +++ b/include/bb2diaspora.php @@ -294,9 +294,9 @@ function bb2diaspora_itemwallwall(&$item) { } -function bb2diaspora_itembody($item) { +function bb2diaspora_itembody($item,$force_update = false) { - if($item['diaspora_meta']) { + if(($item['diaspora_meta']) && (! $force_update)) { $diaspora_meta = json_decode($item['diaspora_meta'],true); if($diaspora_meta) { if(array_key_exists('iv',$diaspora_meta)) { diff --git a/include/diaspora.php b/include/diaspora.php index fb321a813..b35318eac 100755 --- a/include/diaspora.php +++ b/include/diaspora.php @@ -2257,7 +2257,7 @@ function diaspora_send_status($item,$owner,$contact,$public_batch = false) { $images = array(); $title = $item['title']; - $body = bb2diaspora_itembody($item); + $body = bb2diaspora_itembody($item,true); /* // We're trying to match Diaspora's split message/photo protocol but -- cgit v1.2.3 From bc2ad74813b2993e1d7c076181b904b3a5c4be5f Mon Sep 17 00:00:00 2001 From: Klaus Weidenbach Date: Tue, 14 Oct 2014 00:08:55 +0200 Subject: When you delete something in /cloud stay in the right folder. When you deleted a file in /cloud you was always jumped back to /cloud/[channel], now you will stay in the parent folder. Some more doxygen documentation. Removed duplicate data from logging output and reduced logging in RedDAV in general. --- include/RedDAV/RedBasicAuth.php | 25 ++-- include/RedDAV/RedBrowser.php | 8 ++ include/RedDAV/RedDirectory.php | 67 +++++------ include/RedDAV/RedFile.php | 26 +++-- include/attach.php | 244 ++++++++++++++++++++++------------------ include/reddav.php | 34 +++--- 6 files changed, 224 insertions(+), 180 deletions(-) (limited to 'include') diff --git a/include/RedDAV/RedBasicAuth.php b/include/RedDAV/RedBasicAuth.php index c1da73da1..2f86d4f82 100644 --- a/include/RedDAV/RedBasicAuth.php +++ b/include/RedDAV/RedBasicAuth.php @@ -46,7 +46,7 @@ class RedBasicAuth extends DAV\Auth\Backend\AbstractBasic { /** * * @see RedBrowser::set_writeable() - * @var DAV\Browser\Plugin + * @var \Sabre\DAV\Browser\Plugin */ public $browser; /** @@ -85,7 +85,7 @@ class RedBasicAuth extends DAV\Auth\Backend\AbstractBasic { */ protected function validateUserPass($username, $password) { if (trim($password) === '+++') { - logger('(DAV): RedBasicAuth::validateUserPass(): guest ' . $username); + logger('guest: ' . $username); return true; } @@ -112,13 +112,14 @@ class RedBasicAuth extends DAV\Auth\Backend\AbstractBasic { foreach ($x as $record) { if (($record['account_flags'] == ACCOUNT_OK) || ($record['account_flags'] == ACCOUNT_UNVERIFIED) && (hash('whirlpool', $record['account_salt'] . $password) === $record['account_password'])) { - logger('(DAV) RedBasicAuth: password verified for ' . $username); + logger('password verified for ' . $username); return $this->setAuthenticated($r[0]); } } } } - logger('(DAV) RedBasicAuth: password failed for ' . $username); + logger('password failed for ' . $username); + // @TODO add security logger return false; } @@ -186,23 +187,23 @@ class RedBasicAuth extends DAV\Auth\Backend\AbstractBasic { * @brief Set browser plugin for SabreDAV. * * @see RedBrowser::set_writeable() - * @param DAV\Browser\Plugin $browser + * @param \Sabre\DAV\Browser\Plugin $browser */ public function setBrowserPlugin($browser) { $this->browser = $browser; } /** - * Prints out all RedBasicAuth variables to logger(). + * @brief Prints out all RedBasicAuth variables to logger(). * * @return void */ public function log() { - logger('dav: auth: channel_name ' . $this->channel_name, LOGGER_DATA); - logger('dav: auth: channel_id ' . $this->channel_id, LOGGER_DATA); - logger('dav: auth: channel_hash ' . $this->channel_hash, LOGGER_DATA); - logger('dav: auth: observer ' . $this->observer, LOGGER_DATA); - logger('dav: auth: owner_id ' . $this->owner_id, LOGGER_DATA); - logger('dav: auth: owner_nick ' . $this->owner_nick, LOGGER_DATA); + logger('channel_name ' . $this->channel_name, LOGGER_DATA); + logger('channel_id ' . $this->channel_id, LOGGER_DATA); + logger('channel_hash ' . $this->channel_hash, LOGGER_DATA); + logger('observer ' . $this->observer, LOGGER_DATA); + logger('owner_id ' . $this->owner_id, LOGGER_DATA); + logger('owner_nick ' . $this->owner_nick, LOGGER_DATA); } } \ No newline at end of file diff --git a/include/RedDAV/RedBrowser.php b/include/RedDAV/RedBrowser.php index 1f2550ac1..6ec5c978d 100644 --- a/include/RedDAV/RedBrowser.php +++ b/include/RedDAV/RedBrowser.php @@ -262,6 +262,14 @@ class RedBrowser extends DAV\Browser\Plugin { construct_page(get_app()); } + /** + * @brief Returns a human readable formatted string for filesizes. + * + * Don't we need such a functionality in other places, too? + * + * @param int $size filesize in bytes + * @return string + */ function userReadableSize($size) { $ret = ""; if (is_numeric($size)) { diff --git a/include/RedDAV/RedDirectory.php b/include/RedDAV/RedDirectory.php index 72b0fe789..a46b77f5f 100644 --- a/include/RedDAV/RedDirectory.php +++ b/include/RedDAV/RedDirectory.php @@ -49,7 +49,7 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { * @param RedBasicAuth &$auth_plugin */ public function __construct($ext_path, &$auth_plugin) { - logger('RedDirectory::__construct() ' . $ext_path, LOGGER_DATA); + //logger('directory ' . $ext_path, LOGGER_DATA); $this->ext_path = $ext_path; // remove "/cloud" from the beginning of the path $this->red_path = ((strpos($ext_path, '/cloud') === 0) ? substr($ext_path, 6) : $ext_path); @@ -66,19 +66,19 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { } private function log() { - logger('RedDirectory::log() ext_path ' . $this->ext_path, LOGGER_DATA); - logger('RedDirectory::log() os_path ' . $this->os_path, LOGGER_DATA); - logger('RedDirectory::log() red_path ' . $this->red_path, LOGGER_DATA); + logger('ext_path ' . $this->ext_path, LOGGER_DATA); + logger('os_path ' . $this->os_path, LOGGER_DATA); + logger('red_path ' . $this->red_path, LOGGER_DATA); } /** * @brief Returns an array with all the child nodes. * - * @throws DAV\Exception\Forbidden - * @return array DAV\INode[] + * @throw \Sabre\DAV\Exception\Forbidden + * @return array \Sabre\DAV\INode[] */ public function getChildren() { - logger('RedDirectory::getChildren() called for ' . $this->ext_path, LOGGER_DATA); + //logger('children for ' . $this->ext_path, LOGGER_DATA); $this->log(); if (get_config('system', 'block_public') && (! $this->auth->channel_id) && (! $this->auth->observer)) { @@ -97,12 +97,12 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { * @brief Returns a child by name. * * - * @throw DAV\Exception\Forbidden - * @throw DAV\Exception\NotFound + * @throw \Sabre\DAV\Exception\Forbidden + * @throw \Sabre\DAV\Exception\NotFound * @param string $name */ public function getChild($name) { - logger('RedDirectory::getChild(): ' . $name, LOGGER_DATA); + logger($name, LOGGER_DATA); if (get_config('system', 'block_public') && (! $this->auth->channel_id) && (! $this->auth->observer)) { throw new DAV\Exception\Forbidden('Permission denied.'); @@ -130,7 +130,7 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { * @return string */ public function getName() { - logger('RedDirectory::getName() returns: ' . basename($this->red_path), LOGGER_DATA); + //logger(basename($this->red_path), LOGGER_DATA); return (basename($this->red_path)); } @@ -139,20 +139,20 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { * * @todo handle duplicate directory name * - * @throw DAV\Exception\Forbidden + * @throw \Sabre\DAV\Exception\Forbidden * @param string $name The new name of the directory. * @return void */ public function setName($name) { - logger('RedDirectory::setName(): ' . basename($this->red_path) . ' -> ' . $name, LOGGER_DATA); + logger('old name ' . basename($this->red_path) . ' -> ' . $name, LOGGER_DATA); if ((! $name) || (! $this->auth->owner_id)) { - logger('RedDirectory::setName(): permission denied'); + logger('permission denied ' . $name); throw new DAV\Exception\Forbidden('Permission denied.'); } if (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage')) { - logger('RedDirectory::setName(): permission denied'); + logger('permission denied '. $name); throw new DAV\Exception\Forbidden('Permission denied.'); } @@ -177,21 +177,21 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { * After successful creation of the file, you may choose to return the ETag * of the new file here. * - * @throws DAV\Exception\Forbidden + * @throw \Sabre\DAV\Exception\Forbidden * @param string $name Name of the file * @param resource|string $data Initial payload * @return null|string ETag */ public function createFile($name, $data = null) { - logger('RedDirectory::createFile(): ' . $name, LOGGER_DATA); + logger($name, LOGGER_DEBUG); if (! $this->auth->owner_id) { - logger('RedDirectory::createFile(): permission denied'); + logger('permission denied ' . $name); throw new DAV\Exception\Forbidden('Permission denied.'); } if (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage')) { - logger('RedDirectory::createFile(): permission denied'); + logger('permission denied ' . $name); throw new DAV\Exception\Forbidden('Permission denied.'); } @@ -203,7 +203,7 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { ); if (! $c) { - logger('RedDirectory::createFile(): no channel'); + logger('no channel'); throw new DAV\Exception\Forbidden('Permission denied.'); } @@ -237,7 +237,7 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { $size = file_put_contents($f, $data); // delete attach entry if file_put_contents() failed if ($size === false) { - logger('RedDirectory::createFile(): file_put_contents() failed for ' . $name, LOGGER_DEBUG); + logger('file_put_contents() failed to ' . $f); attach_delete($c[0]['channel_id'], $hash); return; } @@ -273,7 +273,7 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { intval($c[0]['channel_account_id']) ); if (($x) && ($x[0]['total'] + $size > $limit)) { - logger('reddav: service class limit exceeded for ' . $c[0]['channel_name'] . ' total usage is ' . $x[0]['total'] . ' limit is ' . $limit); + logger('service class limit exceeded for ' . $c[0]['channel_name'] . ' total usage is ' . $x[0]['total'] . ' limit is ' . $limit); attach_delete($c[0]['channel_id'], $hash); return; } @@ -287,7 +287,7 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { * @return void */ public function createDirectory($name) { - logger('RedDirectory::createDirectory(): ' . $name, LOGGER_DEBUG); + logger($name, LOGGER_DEBUG); if ((! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) { throw new DAV\Exception\Forbidden('Permission denied.'); @@ -301,7 +301,7 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { if ($r) { $result = attach_mkdir($r[0], $this->auth->observer, array('filename' => $name, 'folder' => $this->folder_hash)); if (! $result['success']) { - logger('RedDirectory::createDirectory(): ' . print_r($result, true), LOGGER_DEBUG); + logger('error ' . print_r($result, true), LOGGER_DEBUG); } } } @@ -310,31 +310,33 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { * @brief Checks if a child exists. * * @param string $name + * The name to check if it exists. * @return boolean */ public function childExists($name) { // On /cloud we show a list of available channels. // @todo what happens if no channels are available? if ($this->red_path === '/' && $name === 'cloud') { - logger('RedDirectory::childExists() /cloud: true', LOGGER_DATA); + //logger('We are at /cloud show a channel list', LOGGER_DEBUG); return true; } $x = RedFileData($this->ext_path . '/' . $name, $this->auth, true); - logger('RedFileData returns: ' . print_r($x, true), LOGGER_DATA); + //logger('RedFileData returns: ' . print_r($x, true), LOGGER_DATA); if ($x) return true; + return false; } /** * @todo add description of what this function does. * - * @throw DAV\Exception\NotFound + * @throw \Sabre\DAV\Exception\NotFound * @return void */ function getDir() { - logger('RedDirectory::getDir(): ' . $this->ext_path, LOGGER_DEBUG); + //logger($this->ext_path, LOGGER_DEBUG); $this->auth->log(); $file = $this->ext_path; @@ -356,7 +358,7 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { if (! $path_arr) return; - logger('RedDirectory::getDir(): path: ' . print_r($path_arr, true), LOGGER_DATA); + logger('paths: ' . print_r($path_arr, true), LOGGER_DATA); $channel_name = $path_arr[0]; @@ -367,7 +369,6 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { if (! $r) { throw new DAV\Exception\NotFound('The file with name: ' . $channel_name . ' could not be found.'); - return; } $channel_id = $r[0]['channel_id']; @@ -397,12 +398,11 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { } $this->folder_hash = $folder; $this->os_path = $os_path; - return; } /** * @brief Returns the last modification time for the directory, as a UNIX - * timestamp. + * timestamp. * * It looks for the last edited file in the folder. If it is an empty folder * it returns the lastmodified time of the folder itself, to prevent zero @@ -429,7 +429,8 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { /** * @brief Return quota usage. * - * Do guests relly see the used/free values from filesystem of the complete store directory? + * @fixme Should guests relly see the used/free values from filesystem of the + * complete store directory? * * @return array with used and free values in bytes. */ diff --git a/include/RedDAV/RedFile.php b/include/RedDAV/RedFile.php index 32dbc17e5..f96790631 100644 --- a/include/RedDAV/RedFile.php +++ b/include/RedDAV/RedFile.php @@ -49,7 +49,7 @@ class RedFile extends DAV\Node implements DAV\IFile { $this->data = $data; $this->auth = $auth; - logger('RedFile::__construct(): ' . print_r($this->data, true), LOGGER_DATA); + //logger(print_r($this->data, true), LOGGER_DATA); } /** @@ -58,7 +58,7 @@ class RedFile extends DAV\Node implements DAV\IFile { * @return string */ public function getName() { - logger('RedFile::getName(): ' . basename($this->name), LOGGER_DEBUG); + //logger(basename($this->name), LOGGER_DATA); return basename($this->name); } @@ -70,9 +70,10 @@ class RedFile extends DAV\Node implements DAV\IFile { * @return void */ public function setName($newName) { - logger('RedFile::setName(): ' . basename($this->name) . ' -> ' . $newName, LOGGER_DEBUG); + logger('old name ' . basename($this->name) . ' -> ' . $newName, LOGGER_DATA); if ((! $newName) || (! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) { + logger('permission denied '. $newName); throw new DAV\Exception\Forbidden('Permission denied.'); } @@ -91,7 +92,7 @@ class RedFile extends DAV\Node implements DAV\IFile { * @return void */ public function put($data) { - logger('RedFile::put(): ' . basename($this->name), LOGGER_DEBUG); + logger('put file: ' . basename($this->name), LOGGER_DEBUG); $size = 0; // @todo only 3 values are needed @@ -110,7 +111,7 @@ class RedFile extends DAV\Node implements DAV\IFile { // @todo check return value and set $size directly @file_put_contents($f, $data); $size = @filesize($f); - logger('RedFile::put(): filename: ' . $f . ' size: ' . $size, LOGGER_DEBUG); + logger('filename: ' . $f . ' size: ' . $size, LOGGER_DEBUG); } else { $r = q("UPDATE attach SET data = '%s' WHERE hash = '%s' AND uid = %d LIMIT 1", dbesc(stream_get_contents($data)), @@ -161,7 +162,7 @@ class RedFile extends DAV\Node implements DAV\IFile { intval($c[0]['channel_account_id']) ); if (($x) && ($x[0]['total'] + $size > $limit)) { - logger('RedFile::put(): service class limit exceeded for ' . $c[0]['channel_name'] . ' total usage is ' . $x[0]['total'] . ' limit is ' . $limit); + logger('service class limit exceeded for ' . $c[0]['channel_name'] . ' total usage is ' . $x[0]['total'] . ' limit is ' . $limit); attach_delete($c[0]['channel_id'], $this->data['hash']); return; } @@ -174,7 +175,7 @@ class RedFile extends DAV\Node implements DAV\IFile { * @return string */ public function get() { - logger('RedFile::get(): ' . basename($this->name), LOGGER_DEBUG); + logger('get file ' . basename($this->name), LOGGER_DEBUG); $r = q("SELECT data, flags, filename, filetype FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1", dbesc($this->data['hash']), @@ -206,7 +207,7 @@ class RedFile extends DAV\Node implements DAV\IFile { * * Return null if the ETag can not effectively be determined. * - * @return mixed + * @return null|string */ public function getETag() { $ret = null; @@ -236,6 +237,7 @@ class RedFile extends DAV\Node implements DAV\IFile { * @brief Returns the size of the node, in bytes. * * @return int + * filesize in bytes */ public function getSize() { return $this->data['filesize']; @@ -254,11 +256,13 @@ class RedFile extends DAV\Node implements DAV\IFile { /** * @brief Delete the file. * - * @throw Sabre\DAV\Exception\Forbidden - * @return void + * This method checks the permissions and then calls attach_delete() function + * to actually remove the file. + * + * @throw \Sabre\DAV\Exception\Forbidden */ public function delete() { - logger('RedFile::delete(): ' . basename($this->name), LOGGER_DEBUG); + logger('delete file ' . basename($this->name), LOGGER_DEBUG); if ((! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) { throw new DAV\Exception\Forbidden('Permission denied.'); diff --git a/include/attach.php b/include/attach.php index 0df2e82a5..6bce617cd 100644 --- a/include/attach.php +++ b/include/attach.php @@ -26,77 +26,74 @@ function z_mime_content_type($filename) { $mime_types = array( - 'txt' => 'text/plain', - 'htm' => 'text/html', - 'html' => 'text/html', - 'php' => 'text/html', - 'css' => 'text/css', - 'js' => 'application/javascript', - 'json' => 'application/json', - 'xml' => 'application/xml', - 'swf' => 'application/x-shockwave-flash', - 'flv' => 'video/x-flv', - 'epub' => 'application/epub+zip', - - // images - 'png' => 'image/png', - 'jpe' => 'image/jpeg', - 'jpeg' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'gif' => 'image/gif', - 'bmp' => 'image/bmp', - 'ico' => 'image/vnd.microsoft.icon', - 'tiff' => 'image/tiff', - 'tif' => 'image/tiff', - 'svg' => 'image/svg+xml', - 'svgz' => 'image/svg+xml', - - // archives - 'zip' => 'application/zip', - 'rar' => 'application/x-rar-compressed', - 'exe' => 'application/x-msdownload', - 'msi' => 'application/x-msdownload', - 'cab' => 'application/vnd.ms-cab-compressed', - - // audio/video - 'mp3' => 'audio/mpeg', - 'wav' => 'audio/wav', - 'qt' => 'video/quicktime', - 'mov' => 'video/quicktime', - 'ogg' => 'application/ogg', - - // adobe - 'pdf' => 'application/pdf', - 'psd' => 'image/vnd.adobe.photoshop', - 'ai' => 'application/postscript', - 'eps' => 'application/postscript', - 'ps' => 'application/postscript', - - // ms office - 'doc' => 'application/msword', - 'rtf' => 'application/rtf', - 'xls' => 'application/vnd.ms-excel', - 'ppt' => 'application/vnd.ms-powerpoint', - - - // open office - 'odt' => 'application/vnd.oasis.opendocument.text', - 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + 'txt' => 'text/plain', + 'htm' => 'text/html', + 'html' => 'text/html', + 'php' => 'text/html', + 'css' => 'text/css', + 'js' => 'application/javascript', + 'json' => 'application/json', + 'xml' => 'application/xml', + 'swf' => 'application/x-shockwave-flash', + 'flv' => 'video/x-flv', + 'epub' => 'application/epub+zip', + + // images + 'png' => 'image/png', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'gif' => 'image/gif', + 'bmp' => 'image/bmp', + 'ico' => 'image/vnd.microsoft.icon', + 'tiff' => 'image/tiff', + 'tif' => 'image/tiff', + 'svg' => 'image/svg+xml', + 'svgz' => 'image/svg+xml', + + // archives + 'zip' => 'application/zip', + 'rar' => 'application/x-rar-compressed', + 'exe' => 'application/x-msdownload', + 'msi' => 'application/x-msdownload', + 'cab' => 'application/vnd.ms-cab-compressed', + + // audio/video + 'mp3' => 'audio/mpeg', + 'wav' => 'audio/wav', + 'qt' => 'video/quicktime', + 'mov' => 'video/quicktime', + 'ogg' => 'application/ogg', + + // adobe + 'pdf' => 'application/pdf', + 'psd' => 'image/vnd.adobe.photoshop', + 'ai' => 'application/postscript', + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + + // ms office + 'doc' => 'application/msword', + 'rtf' => 'application/rtf', + 'xls' => 'application/vnd.ms-excel', + 'ppt' => 'application/vnd.ms-powerpoint', + + // open office + 'odt' => 'application/vnd.oasis.opendocument.text', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', ); - $dot = strpos($filename,'.'); - if($dot !== false) { - $ext = strtolower(substr($filename,$dot+1)); + $dot = strpos($filename, '.'); + if ($dot !== false) { + $ext = strtolower(substr($filename, $dot + 1)); if (array_key_exists($ext, $mime_types)) { return $mime_types[$ext]; } } return 'application/octet-stream'; - } - /** * @brief Count files/attachments. * @@ -138,8 +135,8 @@ function attach_count_files($channel_id, $observer, $hash = '', $filename = '', $ret['success'] = ((is_array($r)) ? true : false); $ret['results'] = ((is_array($r)) ? count($r) : false); - return $ret; + return $ret; } /** @@ -190,8 +187,8 @@ function attach_list_files($channel_id, $observer, $hash = '', $filename = '', $ $ret['success'] = ((is_array($r)) ? true : false); $ret['results'] = ((is_array($r)) ? $r : false); - return $ret; + return $ret; } /** @@ -246,8 +243,8 @@ function attach_by_hash($hash, $rev = 0) { $ret['success'] = true; $ret['data'] = $r[0]; - return $ret; + return $ret; } /** @@ -301,7 +298,6 @@ function attach_by_hash_nodata($hash, $rev = 0) { $ret['success'] = true; $ret['data'] = $r[0]; return $ret; - } /** @@ -400,6 +396,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { if(! isset($hash)) $hash = random_string(); + $created = datetime_convert(); if($options === 'replace') { @@ -432,7 +429,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { dbesc($x[0]['deny_cid']), dbesc($x[0]['deny_gid']) ); - } + } elseif($options === 'update') { $r = q("update attach set filename = '%s', filetype = '%s', edited = '%s', allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where id = %d and uid = %d limit 1", @@ -446,7 +443,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { intval($x[0]['id']), intval($x[0]['uid']) ); - } + } else { $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, filetype, filesize, revision, data, created, edited, allow_cid, allow_gid,deny_cid, deny_gid ) VALUES ( %d, %d, '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", @@ -466,7 +463,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { dbesc(($arr && array_key_exists('deny_cid',$arr)) ? $arr['deny_cid'] : ''), dbesc(($arr && array_key_exists('deny_gid',$arr)) ? $arr['deny_gid'] : '') ); - } + } if($options !== 'update') @unlink($src); @@ -490,6 +487,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { $ret['success'] = true; $ret['data'] = $r[0]; + return $ret; } @@ -507,8 +505,8 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { * $ret['data'] = array of attach DB entries without data component */ function z_readdir($channel_id, $observer_hash, $pathname, $parent_hash = '') { - $ret = array('success' => false); + if(! perm_is_allowed($r[0]['uid'], get_observer_hash(), 'view_storage')) { $ret['message'] = t('Permission denied.'); return $ret; @@ -547,6 +545,7 @@ function z_readdir($channel_id, $observer_hash, $pathname, $parent_hash = '') { } $ret['success'] = true; $ret['data'] = $r; + return $ret; } @@ -686,7 +685,6 @@ function attach_mkdir($channel, $observer_hash, $arr = null) { } return $ret; - } /** @@ -732,15 +730,19 @@ function attach_change_permissions($channel_id, $resource, $allow_cid, $allow_gi dbesc($resource), intval($channel_id) ); - - return; } /** - * @brief Delete a file/directory. - * + * @brief Delete a file/directory from a channel. + * + * If the provided resource hash is from a directory it will delete everything + * recursively under this directory. + * * @param int $channel_id - * @param string $resource a hash to delete + * The id of the channel + * @param string $resource + * The hash to delete + * @return void */ function attach_delete($channel_id, $resource) { @@ -760,7 +762,7 @@ function attach_delete($channel_id, $resource) { // If resource is a directory delete everything in the directory recursive if($r[0]['flags'] & ATTACH_FLAG_DIR) { - $x = q("select hash, flags from attach where folder = '%s' and uid = %d", + $x = q("SELECT hash, flags FROM attach WHERE folder = '%s' AND uid = %d", dbesc($resource), intval($channel_id) ); @@ -799,19 +801,21 @@ function attach_delete($channel_id, $resource) { dbesc($r[0]['folder']), intval($channel_id) ); - - return; } /** * @brief Returns path to file in cloud/. * - * @param $arr - * @return string with the path the file to cloud/ + * @param array + * $arr[uid] int the channels uid + * $arr[folder] string + * $arr[filename]] string + * @return string + * path to the file in cloud/ */ function get_cloudpath($arr) { - $basepath = 'cloud/'; + if($arr['uid']) { $r = q("select channel_address from channel where channel_id = %d limit 1", intval($arr['uid']) @@ -823,7 +827,6 @@ function get_cloudpath($arr) { $path = $basepath; if($arr['folder']) { - $lpath = ''; $lfile = $arr['folder']; @@ -842,60 +845,83 @@ function get_cloudpath($arr) { $lpath = $r[0]['filename'] . '/' . $lpath; $lfile = $r[0]['folder']; - } while ( ($r[0]['folder']) && ($r[0]['flags'] & ATTACH_FLAG_DIR)) ; + } while ( ($r[0]['folder']) && ($r[0]['flags'] & ATTACH_FLAG_DIR)); - $path .= $lpath; + $path .= $lpath; } - $path .= $arr['filename']; + return $path; } /** * @brief Returns path to parent folder in cloud/. - * - * @param $arr - * @return string with the folder path + * + * @param int $channel_id + * The id of the channel + * @param string $channel_name + * The name of the channel + * @param string $attachHash + * @return string with the full folder path */ function get_parent_cloudpath($channel_id, $channel_name, $attachHash) { - //Build directory tree and redirect + // build directory tree $parentHash = $attachHash; do { $parentHash = find_folder_hash_by_attach_hash($channel_id, $parentHash); if ($parentHash) { $parentName = find_filename_by_hash($channel_id, $parentHash); - $parentFullPath = $parentName."/".$parentFullPath; + $parentFullPath = $parentName . '/' . $parentFullPath; } } while ($parentHash); - $parentFullPath = z_root() . "/cloud/" . $channel_name . "/" . $parentFullPath; + $parentFullPath = z_root() . '/cloud/' . $channel_name . '/' . $parentFullPath; + return $parentFullPath; } + +/** + * @brief Return the hash of an attachment's folder. + * + * @param int $channel_id + * The id of the channel + * @param string $attachHash + * The hash of the attachment + * @return string + */ function find_folder_hash_by_attach_hash($channel_id, $attachHash) { - $r = q("select * from attach where uid = %d and hash = '%s' limit 1", - intval($channel_id), dbesc($attachHash) + $r = q("SELECT folder FROM attach WHERE uid = %d AND hash = '%s' LIMIT 1", + intval($channel_id), + dbesc($attachHash) ); - $hash = ""; - if($r) { - foreach($r as $rr) { - $hash = $rr['folder']; - } + $hash = ''; + if ($r) { + $hash = $r[0]['folder']; } - return $hash; + return $hash; } + +/** + * @brief Returns the filename of an attachment in a given channel. + * + * @param mixed $channel_id + * The id of the channel + * @param mixed $attachHash + * The hash of the attachment + * @return string + * The filename of the attachment + */ function find_filename_by_hash($channel_id, $attachHash) { - $r = q("select * from attach where uid = %d and hash = '%s' limit 1", - intval($channel_id), dbesc($attachHash) + $r = q("SELECT filename FROM attach WHERE uid = %d AND hash = '%s' LIMIT 1", + intval($channel_id), + dbesc($attachHash) ); - $filename = ""; - if($r) { - foreach($r as $rr) { - $filename = $rr['filename']; - } + $filename = ''; + if ($r) { + $filename = $r[0]['filename']; } - return $filename; + return $filename; } - /** * * @param $in @@ -904,6 +930,6 @@ function find_filename_by_hash($channel_id, $attachHash) { function pipe_streams($in, $out) { $size = 0; while (!feof($in)) - $size += fwrite($out, fread($in,8192)); + $size += fwrite($out, fread($in, 8192)); return $size; } diff --git a/include/reddav.php b/include/reddav.php index 6785131c6..86b3a00e4 100644 --- a/include/reddav.php +++ b/include/reddav.php @@ -36,8 +36,8 @@ require_once('include/RedDAV/RedBasicAuth.php'); * @todo Is there any reason why this is not inside RedDirectory class? * @fixme function name looks like a class name, should we rename it? * - * @param $auth - * @return array containing RedDirectory objects + * @param RedBasicAuth &$auth + * @return array RedDirectory[] */ function RedChannelList(&$auth) { $ret = array(); @@ -50,7 +50,7 @@ function RedChannelList(&$auth) { if ($r) { foreach ($r as $rr) { if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage')) { - logger('RedChannelList: ' . '/cloud/' . $rr['channel_address'], LOGGER_DATA); + logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DEBUG); // @todo can't we drop '/cloud'? It gets stripped off anyway in RedDirectory $ret[] = new RedDAV\RedDirectory('/cloud/' . $rr['channel_address'], $auth); } @@ -70,8 +70,10 @@ function RedChannelList(&$auth) { * @fixme function name looks like a class name, should we rename it? * * @param string $file path to a directory - * @param &$auth - * @returns array DAV\INode[] + * @param RedBasicAuth &$auth + * @returns null|array \Sabre\DAV\INode[] + * @throw \Sabre\DAV\Exception\Forbidden + * @throw \Sabre\DAV\Exception\NotFound */ function RedCollectionData($file, &$auth) { $ret = array(); @@ -88,7 +90,7 @@ function RedCollectionData($file, &$auth) { $file = trim($file, '/'); $path_arr = explode('/', $file); - + if (! $path_arr) return null; @@ -150,7 +152,7 @@ function RedCollectionData($file, &$auth) { // This should no longer be needed since we just returned errors for paths not found if ($path !== '/' . $file) { - logger("RedCollectionData: Path mismatch: $path !== /$file"); + logger("Path mismatch: $path !== /$file"); return NULL; } @@ -160,8 +162,7 @@ function RedCollectionData($file, &$auth) { ); foreach ($r as $rr) { - logger('RedCollectionData: filename: ' . $rr['filename'], LOGGER_DATA); - + //logger('filename: ' . $rr['filename'], LOGGER_DEBUG); if ($rr['flags'] & ATTACH_FLAG_DIR) { // @todo can't we drop '/cloud'? it gets stripped off anyway in RedDirectory $ret[] = new RedDAV\RedDirectory('/cloud' . $path . '/' . $rr['filename'], $auth); @@ -180,11 +181,14 @@ function RedCollectionData($file, &$auth) { * @fixme function name looks like a class name, should we rename it? * * @param string $file - * @param &$auth + * path to file or directory + * @param RedBasicAuth &$auth * @param boolean $test (optional) enable test mode + * @return RedFile|RedDirectory|boolean|null + * @throw \Sabre\DAV\Exception\Forbidden */ function RedFileData($file, &$auth, $test = false) { - logger('RedFileData:' . $file . (($test) ? ' (test mode) ' : ''), LOGGER_DEBUG); + logger($file . (($test) ? ' (test mode) ' : ''), LOGGER_DEBUG); $x = strpos($file, '/cloud'); if ($x === 0) { @@ -198,7 +202,7 @@ function RedFileData($file, &$auth, $test = false) { $file = trim($file, '/'); $path_arr = explode('/', $file); - + if (! $path_arr) return null; @@ -237,7 +241,7 @@ function RedFileData($file, &$auth, $test = false) { if ($r && ( $r[0]['flags'] & ATTACH_FLAG_DIR)) { $folder = $r[0]['hash']; $path = $path . '/' . $r[0]['filename']; - } + } if (! $r) { $r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, created, edited from attach where folder = '%s' and filename = '%s' and uid = %d $perms group by filename limit 1", @@ -267,11 +271,11 @@ function RedFileData($file, &$auth, $test = false) { } if ($errors) { - logger('RedFileData: not found'); + logger('not found ' . $file); if ($test) return false; if ($permission_error) { - logger('RedFileData: permission error'); + logger('permission error ' . $file); throw new DAV\Exception\Forbidden('Permission denied.'); } return; -- cgit v1.2.3 From 1b0390af0659e0c5534acbee97db1ef3c1e65288 Mon Sep 17 00:00:00 2001 From: friendica Date: Mon, 13 Oct 2014 15:27:03 -0700 Subject: new function hubloc_change_primary() --- include/hubloc.php | 42 ++++++++++++++++++++++++++++++++++++++++++ include/zot.php | 21 ++++++++++++++++++--- 2 files changed, 60 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/hubloc.php b/include/hubloc.php index fded434d2..89ec6231d 100644 --- a/include/hubloc.php +++ b/include/hubloc.php @@ -113,4 +113,46 @@ function remove_obsolete_hublocs() { } +function hubloc_change_primary($hubloc) { + + if(! is_array($hubloc)) + return false; + if(! $hubloc['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY) + return false; + + // See if there's a local channel + + $r = q("select channel_id, channel_primary from channel where channel_hash = '%s' limit 1", + dbesc($hubloc['hubloc_hash']) + ); + if(($r) && (! $r[0]['channel_primary'])) { + q("update channel set channel_primary = 1 where channel_id = %d limit 1", + intval($r[0]['channel_id']) + ); + } + + // do we even have an xchan for this hubloc and if so is it already set as primary? + + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($hubloc['hubloc_hash']) + ); + if(! $r) + return false; + if($r[0]['xchan_addr'] === $hubloc['hubloc_addr']) + return false; + + $url = $hubloc['hubloc_url']; + $lwebbie = substr($hubloc['hubloc_addr'],0,strpos($hubloc['hubloc_addr'],'@')); + + $r = q("update xchan set xchan_addr, xchan_url = '%s', xchan_follow = '%s', xchan_connurl = '%s', where xchan_hash = '%s' limit 1", + dbesc($hubloc['hubloc_addr']), + dbesc($url . '/channel/' . $lwebbie), + dbesc($url . '/follow?f=&url=%s'), + dbesc($url . '/poco/' . $lwebbie), + dbesc($hubloc['hubloc_hash']) + ); + + return true; + +} \ No newline at end of file diff --git a/include/zot.php b/include/zot.php index 2d674c354..ff3bacafe 100644 --- a/include/zot.php +++ b/include/zot.php @@ -2,6 +2,7 @@ require_once('include/crypto.php'); require_once('include/items.php'); +require_once('include/hubloc.php'); /** * Red implementation of zot protocol. @@ -1714,9 +1715,14 @@ function process_location_delivery($sender,$arr,$deliveries) { ); if($r) $sender['key'] = $r[0]['xchan_pubkey']; - - $x = sync_locations($sender,$arr,true); - logger('process_location_delivery: results: ' . print_r($x,true), LOGGER_DEBUG); + if(array_key_exists('locations',$arr) && $arr['locations']) { + $x = sync_locations($sender,$arr,true); + logger('process_location_delivery: results: ' . print_r($x,true), LOGGER_DEBUG); + if($x['changed']) { + $guid = random_string() . '@' . get_app()->get_hostname(); + update_modtime($sender['hash'],$sender['guid'],$arr['locations'][0]['address'],UPDATE_FLAGS_UPDATED); + } + } } @@ -1837,6 +1843,7 @@ function sync_locations($sender,$arr,$absolute = false) { dbesc(datetime_convert()), intval($r[0]['hubloc_id']) ); + hubloc_change_primary($r[0]); $what .= 'primary_hub '; $changed = true; } @@ -1884,6 +1891,14 @@ function sync_locations($sender,$arr,$absolute = false) { $what .= 'newhub '; $changed = true; + if($location['primary']) { + $r = q("select * from hubloc where hubloc_addr = '%s' and hubloc_sitekey = '%s' limit 1", + dbesc($location['address']), + dbesc($location['sitekey']) + ); + if($r) + hubloc_change_primary($r[0]); + } } // get rid of any hubs we have for this channel which weren't reported. -- cgit v1.2.3 From 6503b911316d9573ba06b90fe45d8757488d464e Mon Sep 17 00:00:00 2001 From: friendica Date: Mon, 13 Oct 2014 16:12:32 -0700 Subject: sql --- include/hubloc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/hubloc.php b/include/hubloc.php index 89ec6231d..1906833c5 100644 --- a/include/hubloc.php +++ b/include/hubloc.php @@ -144,7 +144,7 @@ function hubloc_change_primary($hubloc) { $url = $hubloc['hubloc_url']; $lwebbie = substr($hubloc['hubloc_addr'],0,strpos($hubloc['hubloc_addr'],'@')); - $r = q("update xchan set xchan_addr, xchan_url = '%s', xchan_follow = '%s', xchan_connurl = '%s', where xchan_hash = '%s' limit 1", + $r = q("update xchan set xchan_addr = '%s', xchan_url = '%s', xchan_follow = '%s', xchan_connurl = '%s' where xchan_hash = '%s' limit 1", dbesc($hubloc['hubloc_addr']), dbesc($url . '/channel/' . $lwebbie), dbesc($url . '/follow?f=&url=%s'), -- cgit v1.2.3 From 3d56bb5cd72e2ca6d07fa4b79c4049b7c339af86 Mon Sep 17 00:00:00 2001 From: friendica Date: Mon, 13 Oct 2014 16:21:02 -0700 Subject: this bug has been there for a *long* time. First time I've ever seen it triggered. --- include/network.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/network.php b/include/network.php index 7286f0b12..25ed615c6 100644 --- a/include/network.php +++ b/include/network.php @@ -402,7 +402,7 @@ function validate_email($addr) { return false; $h = substr($addr,strpos($addr,'@') + 1); - if(($h) && (dns_get_record($h, DNS_A + DNS_CNAME + DNS_PTR + DNS_MX) || filter_var($h['host'], FILTER_VALIDATE_IP) )) { + if(($h) && (dns_get_record($h, DNS_A + DNS_CNAME + DNS_PTR + DNS_MX) || filter_var($h, FILTER_VALIDATE_IP) )) { return true; } return false; -- cgit v1.2.3 From 8a907a789f080ccae45e5b44d0bc43ed65477e07 Mon Sep 17 00:00:00 2001 From: friendica Date: Mon, 13 Oct 2014 17:59:03 -0700 Subject: more diagnostic when changing primary --- include/hubloc.php | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/hubloc.php b/include/hubloc.php index 1906833c5..735aad432 100644 --- a/include/hubloc.php +++ b/include/hubloc.php @@ -115,10 +115,16 @@ function remove_obsolete_hublocs() { function hubloc_change_primary($hubloc) { - if(! is_array($hubloc)) + if(! is_array($hubloc)) { + logger('no hubloc'); return false; - if(! $hubloc['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY) + } + if(! ($hubloc['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY)) { + logger('not primary: ' . $hubloc['hubloc_url']); return false; + } + + logger('setting primary: ' . $hubloc['hubloc_url']); // See if there's a local channel @@ -136,10 +142,14 @@ function hubloc_change_primary($hubloc) { $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($hubloc['hubloc_hash']) ); - if(! $r) + if(! $r) { + logger('xchan not found'); return false; - if($r[0]['xchan_addr'] === $hubloc['hubloc_addr']) + } + if($r[0]['xchan_addr'] === $hubloc['hubloc_addr']) { + logger('xchan already changed'); return false; + } $url = $hubloc['hubloc_url']; $lwebbie = substr($hubloc['hubloc_addr'],0,strpos($hubloc['hubloc_addr'],'@')); @@ -151,7 +161,10 @@ function hubloc_change_primary($hubloc) { dbesc($url . '/poco/' . $lwebbie), dbesc($hubloc['hubloc_hash']) ); + if(! $r) + logger('xchan_update failed.'); + logger('primary hubloc changed.' . print_r($hubloc,true),LOGGER_DEBUG); return true; } -- cgit v1.2.3 From bd4dd85fbbe7bb0bc36b8a7d51e991ef3b5770fa Mon Sep 17 00:00:00 2001 From: friendica Date: Mon, 13 Oct 2014 20:53:34 -0700 Subject: there's the problem --- include/zot.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/zot.php b/include/zot.php index ff3bacafe..aea8a992a 100644 --- a/include/zot.php +++ b/include/zot.php @@ -1838,7 +1838,7 @@ function sync_locations($sender,$arr,$absolute = false) { if((($r[0]['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY) && (! $location['primary'])) || ((! ($r[0]['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY)) && ($location['primary']))) { - $r = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_id = %d limit 1", + $m = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_id = %d limit 1", intval(HUBLOC_FLAGS_PRIMARY), dbesc(datetime_convert()), intval($r[0]['hubloc_id']) @@ -1849,7 +1849,7 @@ function sync_locations($sender,$arr,$absolute = false) { } if((($r[0]['hubloc_flags'] & HUBLOC_FLAGS_DELETED) && (! $location['deleted'])) || ((! ($r[0]['hubloc_flags'] & HUBLOC_FLAGS_DELETED)) && ($location['deleted']))) { - $r = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_id = %d limit 1", + $n = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_id = %d limit 1", intval(HUBLOC_FLAGS_DELETED), dbesc(datetime_convert()), intval($r[0]['hubloc_id']) -- cgit v1.2.3 From 19e1b95837f46bb2ed46978f5b96a3c4fe150c2a Mon Sep 17 00:00:00 2001 From: friendica Date: Mon, 13 Oct 2014 21:01:51 -0700 Subject: don't use cached data --- include/zot.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/zot.php b/include/zot.php index aea8a992a..2400643a7 100644 --- a/include/zot.php +++ b/include/zot.php @@ -1843,6 +1843,8 @@ function sync_locations($sender,$arr,$absolute = false) { dbesc(datetime_convert()), intval($r[0]['hubloc_id']) ); + // make sure hubloc_change_primary() has current data + $r[0]['hubloc_flags'] = $r[0]['hubloc_flags'] ^ HUBLOC_FLAGS_PRIMARY; hubloc_change_primary($r[0]); $what .= 'primary_hub '; $changed = true; -- cgit v1.2.3 From 0057612a9f9ecb49c2bd69e550827e2304c85204 Mon Sep 17 00:00:00 2001 From: friendica Date: Mon, 13 Oct 2014 21:38:36 -0700 Subject: figuring out how to bootstrap the change_primary procedure when all you have is inconsistent data which you think you trust. --- include/hubloc.php | 2 ++ include/zot.php | 4 ++++ 2 files changed, 6 insertions(+) (limited to 'include') diff --git a/include/hubloc.php b/include/hubloc.php index 735aad432..04c29315a 100644 --- a/include/hubloc.php +++ b/include/hubloc.php @@ -113,6 +113,8 @@ function remove_obsolete_hublocs() { } +// This actually changes other structures to match the given (presumably current) hubloc primary selection + function hubloc_change_primary($hubloc) { if(! is_array($hubloc)) { diff --git a/include/zot.php b/include/zot.php index 2400643a7..0338f0ea2 100644 --- a/include/zot.php +++ b/include/zot.php @@ -1849,6 +1849,10 @@ function sync_locations($sender,$arr,$absolute = false) { $what .= 'primary_hub '; $changed = true; } + elseif($absolute) { + // Absolute sync - make sure the current primary is correctly reflected in the xchan + hubloc_change_primary($r[0]); + } if((($r[0]['hubloc_flags'] & HUBLOC_FLAGS_DELETED) && (! $location['deleted'])) || ((! ($r[0]['hubloc_flags'] & HUBLOC_FLAGS_DELETED)) && ($location['deleted']))) { $n = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_id = %d limit 1", -- cgit v1.2.3 From 903f7e73fbc9a36c0a073ff1c9f05555a030a34e Mon Sep 17 00:00:00 2001 From: friendica Date: Mon, 13 Oct 2014 21:44:46 -0700 Subject: if a hubloc primary change results in an xchan primary change, create a directory update packet. --- include/zot.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/zot.php b/include/zot.php index 0338f0ea2..869bca668 100644 --- a/include/zot.php +++ b/include/zot.php @@ -1851,7 +1851,11 @@ function sync_locations($sender,$arr,$absolute = false) { } elseif($absolute) { // Absolute sync - make sure the current primary is correctly reflected in the xchan - hubloc_change_primary($r[0]); + $pr = hubloc_change_primary($r[0]); + if($pr) { + $what .= 'xchan_primary'; + $changed = true; + } } if((($r[0]['hubloc_flags'] & HUBLOC_FLAGS_DELETED) && (! $location['deleted'])) || ((! ($r[0]['hubloc_flags'] & HUBLOC_FLAGS_DELETED)) && ($location['deleted']))) { -- cgit v1.2.3 From 2db7d88e285f2deb6d75d961bccfa396cd4eaae6 Mon Sep 17 00:00:00 2001 From: friendica Date: Tue, 14 Oct 2014 18:02:34 -0700 Subject: this is the reason Diaspora forum tagging was broken --- include/identity.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/identity.php b/include/identity.php index 4417f4028..07bfaebbd 100644 --- a/include/identity.php +++ b/include/identity.php @@ -291,8 +291,8 @@ function create_identity($arr) { // Create a verified hub location pointing to this site. $r = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_flags, - hubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey ) - values ( '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s' )", + hubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey, hubloc_network ) + values ( '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s' )", dbesc($guid), dbesc($sig), dbesc($hash), @@ -302,7 +302,8 @@ function create_identity($arr) { dbesc(base64url_encode(rsa_sign(z_root(),$ret['channel']['channel_prvkey']))), dbesc(get_app()->get_hostname()), dbesc(z_root() . '/post'), - dbesc(get_config('system','pubkey')) + dbesc(get_config('system','pubkey')), + dbesc('zot') ); if(! $r) logger('create_identity: Unable to store hub location'); -- cgit v1.2.3 From 65b84e839a2acfad2f86c1ed40c9fdc67e4fc8ed Mon Sep 17 00:00:00 2001 From: friendica Date: Tue, 14 Oct 2014 18:47:08 -0700 Subject: back to wrestling with the !@#$ diaspora recursive reshare from hell --- include/diaspora.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/diaspora.php b/include/diaspora.php index b35318eac..c6d4b7423 100755 --- a/include/diaspora.php +++ b/include/diaspora.php @@ -927,9 +927,14 @@ function get_diaspora_reshare_xml($url,$recurse = 0) { // see if it's a reshare of a reshare - if($source_xml->root_diaspora_id && $source_xml->root_guid && $recurse < 15) { - $orig_author = notags(unxmlify($source_xml->root_diaspora_id)); - $orig_guid = notags(unxmlify($source_xml->root_guid)); + if($source_xml->post->reshare) + $xml = $source_xml->post->reshare; + else + return false; + + if($xml->root_diaspora_id && $xml->root_guid && $recurse < 15) { + $orig_author = notags(unxmlify($xml->root_diaspora_id)); + $orig_guid = notags(unxmlify($xml->root_guid)); $source_url = 'https://' . substr($orig_author,strpos($orig_author,'@')+1) . '/p/' . $orig_guid . '.xml'; $y = get_diaspora_reshare_xml($source_url,$recurse+1); if($y) -- cgit v1.2.3 From e80c20d2584e17b43dd456bbb4b3dc0f8c11eeb4 Mon Sep 17 00:00:00 2001 From: friendica Date: Wed, 15 Oct 2014 17:55:20 -0700 Subject: Don't recognise hashtags starting with #, e.g. ### --- include/text.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/text.php b/include/text.php index 0e38de2d2..fca23ca22 100644 --- a/include/text.php +++ b/include/text.php @@ -619,8 +619,8 @@ function get_tags($s) { } if(substr($mtch,-1,1) === '.') $mtch = substr($mtch,0,-1); - // ignore strictly numeric tags like #1 - if((strpos($mtch,'#') === 0) && ( ctype_digit(substr($mtch,1)) || substr($mtch,1,1) === '^')) + // ignore strictly numeric tags like #1 or #^ bookmarks or ## double hash + if((strpos($mtch,'#') === 0) && ( ctype_digit(substr($mtch,1)) || substr($mtch,1,1) === '^') || substr($mtch,1,1) === '#') continue; // try not to catch url fragments if(strpos($s,$mtch) && preg_match('/[a-zA-z0-9\/]/',substr($s,strpos($s,$mtch)-1,1))) -- cgit v1.2.3 From ae9e1fa688c90e128637b5c44cf4705287f6cfa1 Mon Sep 17 00:00:00 2001 From: friendica Date: Wed, 15 Oct 2014 18:35:56 -0700 Subject: missing event permissions --- include/acl_selectors.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/acl_selectors.php b/include/acl_selectors.php index 0b68ba227..3cdbd411c 100644 --- a/include/acl_selectors.php +++ b/include/acl_selectors.php @@ -248,7 +248,8 @@ function populate_acl($defaults = null,$show_jotnets = true) { '$aclModalTitle' => t('Permissions'), '$aclModalDismiss' => t('Close') )); - + + logger($o); return $o; -- cgit v1.2.3 From 4cbe69685965eaa8900d927a55487599b4683b2e Mon Sep 17 00:00:00 2001 From: friendica Date: Wed, 15 Oct 2014 18:36:36 -0700 Subject: remove log statement --- include/acl_selectors.php | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/acl_selectors.php b/include/acl_selectors.php index 3cdbd411c..5adafff2c 100644 --- a/include/acl_selectors.php +++ b/include/acl_selectors.php @@ -249,8 +249,6 @@ function populate_acl($defaults = null,$show_jotnets = true) { '$aclModalDismiss' => t('Close') )); - logger($o); - return $o; } -- cgit v1.2.3 From e1f88fd15d75f81af5017860b9f197771326c9b7 Mon Sep 17 00:00:00 2001 From: friendica Date: Thu, 16 Oct 2014 02:02:11 -0700 Subject: jsonp support (thankxs fabrixxm) --- include/api.php | 5 ++++- include/taxonomy.php | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/api.php b/include/api.php index 2505def4c..8b52253dd 100644 --- a/include/api.php +++ b/include/api.php @@ -197,7 +197,10 @@ require_once('include/items.php'); case "json": header ("Content-Type: application/json"); foreach($r as $rr) - return json_encode($rr); + $json = json_encode($rr); + if ($_GET['callback']) + $json = $_GET['callback']."(".$json.")"; + return $json; break; case "rss": header ("Content-Type: application/rss+xml"); diff --git a/include/taxonomy.php b/include/taxonomy.php index 92003328f..35605da22 100644 --- a/include/taxonomy.php +++ b/include/taxonomy.php @@ -154,7 +154,7 @@ function tagadelic($uid, $count = 0, $authors = '', $flags = 0, $restrict = 0, $ } function tags_sort($a,$b) { - if($a[0] == $b[0]) + if(strtolower($a[0]) == strtolower($b[0])) return 0; return((strtolower($a[0]) < strtolower($b[0])) ? -1 : 1); } -- cgit v1.2.3 From 6867a8a7f6060c82cba3a34cd944a3737e8e263e Mon Sep 17 00:00:00 2001 From: Stefan Parviainen Date: Thu, 16 Oct 2014 17:21:37 +0200 Subject: Login menu --- include/nav.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/nav.php b/include/nav.php index 4f7d609aa..ba817648b 100644 --- a/include/nav.php +++ b/include/nav.php @@ -84,6 +84,7 @@ EOT; $nav['usermenu']=array(); $userinfo = null; + $nav['loginmenu']=array(); if(local_user()) { @@ -120,8 +121,9 @@ EOT; $nav['usermenu'][] = Array('webpages/' . $channel['channel_address'],t('Webpages'),"",t('Your webpages')); } else { - if(! get_account_id()) - $nav['login'] = Array('login',t('Login'), ($a->module == 'login'?'selected':''), t('Sign in')); + if(! get_account_id()) { + $nav['loginmenu'][] = Array('login',t('Login'),'',t('Sign in')); + } else $nav['alogout'] = Array('logout',t('Logout'), "", t('End this session')); @@ -136,14 +138,11 @@ EOT; } if($observer) { - $nav['locked'] = true; $nav['lock'] = array('logout','','lock', sprintf( t('%s - click to logout'), $observer['xchan_addr'])); } else { - $nav['locked'] = false; - $nav['lock'] = array('rmagic','','unlock', - t('Click to authenticate to your home hub')); + $nav['loginmenu'][] = Array('rmagic',t('Remote login'),'',t('Click to authenticate to your home hub')); } /** -- cgit v1.2.3 From 7bbe700f3f170cc4527131165a9b9ab1f99e5cd1 Mon Sep 17 00:00:00 2001 From: friendica Date: Thu, 16 Oct 2014 16:19:19 -0700 Subject: mark signature forgeries --- include/ItemObject.php | 4 +++- include/conversation.php | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/ItemObject.php b/include/ItemObject.php index 7c75e35bd..90c036def 100644 --- a/include/ItemObject.php +++ b/include/ItemObject.php @@ -191,7 +191,8 @@ class Item extends BaseObject { } - $verified = (($item['item_flags'] & ITEM_VERIFIED) ? t('Message is verified') : ''); + $verified = (($item['item_flags'] & ITEM_VERIFIED) ? t('Message signature validated') : ''); + $forged = ((($item['sig']) && (! ($item['item_flags'] & ITEM_VERIFIED))) ? t('Message signature incorrect') : ''); $unverified = '' ; // (($this->is_wall_to_wall() && (! ($item['item_flags'] & ITEM_VERIFIED))) ? t('Message cannot be verified') : ''); @@ -269,6 +270,7 @@ class Item extends BaseObject { 'lock' => $lock, 'verified' => $verified, 'unverified' => $unverified, + 'forged' => $forged, 'location' => $location, 'indent' => $indent, 'owner_url' => $this->get_owner_url(), diff --git a/include/conversation.php b/include/conversation.php index 92ba18d13..b22b570a1 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -649,7 +649,10 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ $likebuttons = false; $shareable = false; - $verified = (($item['item_flags'] & ITEM_VERIFIED) ? t('Message is verified') : ''); + $verified = (($item['item_flags'] & ITEM_VERIFIED) ? t('Message signature validated') : ''); + $forged = ((($item['sig']) && (! ($item['item_flags'] & ITEM_VERIFIED))) ? t('Message signature incorrect') : ''); + + $unverified = ''; @@ -682,6 +685,7 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ 'mentions' => $mentions, 'verified' => $verified, 'unverified' => $unverified, + 'forged' => $forged, 'txt_cats' => t('Categories:'), 'txt_folders' => t('Filed under:'), 'has_cats' => ((count($categories)) ? 'true' : ''), -- cgit v1.2.3 From e8be2ff8daff6c0acae69dff5138d1edc6ef87bb Mon Sep 17 00:00:00 2001 From: friendica Date: Sun, 19 Oct 2014 15:54:20 -0700 Subject: wall-e random signature failures --- include/html2bbcode.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/html2bbcode.php b/include/html2bbcode.php index df430e6c7..6d6e6333b 100644 --- a/include/html2bbcode.php +++ b/include/html2bbcode.php @@ -283,8 +283,9 @@ function html2bbcode($message) array('[b]', '[/b]', '[i]', '[/i]'), $message); // Handling Yahoo style of mails - $message = str_replace('[hr][b]From:[/b]', '[quote][b]From:[/b]', $message); + // $message = str_replace('[hr][b]From:[/b]', '[quote][b]From:[/b]', $message); + $message = htmlspecialchars($message,ENT_COMPAT,'UTF-8',false); return(trim($message)); } -- cgit v1.2.3 From bae3029c639bf6f9469dd93bfedc3dce0d8510d7 Mon Sep 17 00:00:00 2001 From: friendica Date: Sun, 19 Oct 2014 16:12:05 -0700 Subject: merge madness --- include/datetime.php | 181 ++++++++++++++++++++------------------------------- include/nav.php | 2 +- 2 files changed, 73 insertions(+), 110 deletions(-) (limited to 'include') diff --git a/include/datetime.php b/include/datetime.php index 84ab1e2fa..fe0f29c7a 100644 --- a/include/datetime.php +++ b/include/datetime.php @@ -130,135 +130,98 @@ function datetime_convert($from = 'UTC', $to = 'UTC', $s = 'now', $fmt = "Y-m-d function dob($dob) { list($year,$month,$day) = sscanf($dob,'%4d-%2d-%2d'); - $y = datetime_convert('UTC',date_default_timezone_get(),'now','Y'); $f = get_config('system','birthday_input_format'); if(! $f) $f = 'ymd'; - $o = datesel($f,'',1920,$y,true,$year,$month,$day); - return $o; -} - -function datesel_format($f) { - - $o = ''; + $o = datesel($f,mktime(0,0,0,0,0,1900),mktime(),mktime(0,0,0,$month,$day,$year),'dob'); - if(strlen($f)) { - for($x = 0; $x < strlen($f); $x ++) { - switch($f[$x]) { - case 'y': - if(strlen($o)) - $o .= '-'; - $o .= t('year'); - break; - case 'm': - if(strlen($o)) - $o .= '-'; - $o .= t('month'); - break; - case 'd': - if(strlen($o)) - $o .= '-'; - $o .= t('day'); - break; - default: - break; - } - } - } return $o; } -// returns a date selector. -// $f = format string, e.g. 'ymd' or 'mdy' -// $pre = prefix (if needed) for HTML name and class fields -// $ymin = first year shown in selector dropdown -// $ymax = last year shown in selector dropdown -// $allow_blank = allow an empty response on any field -// $y = already selected year -// $m = already selected month -// $d = already selected day - +/** + * returns a date selector + * @param $format + * format string, e.g. 'ymd' or 'mdy'. Not currently supported + * @param $min + * unix timestamp of minimum date + * @param $max + * unix timestap of maximum date + * @param $default + * unix timestamp of default date + * @param $id + * id and name of datetimepicker (defaults to "datetimepicker") + */ +function datesel($format, $min, $max, $default,$id = 'datepicker') { + return datetimesel($format,$min,$max,$default,$id,true,false); +} -function datesel($f,$pre,$ymin,$ymax,$allow_blank,$y,$m,$d) { +/** + * returns a date selector + * @param $format + * format string, e.g. 'ymd' or 'mdy'. Not currently supported + * @param $h + * already selected hour + * @param $m + * already selected minute + * @param $id + * id and name of datetimepicker (defaults to "timepicker") + */ +function timesel($format,$h,$m,$id='timepicker') { + return datetimesel($format,mktime(),mktime(),mktime($h,$m),$id,false,true); +} +/** + * returns a datetime selector + * @param $format + * format string, e.g. 'ymd' or 'mdy'. Not currently supported + * @param $min + * unix timestamp of minimum date + * @param $max + * unix timestap of maximum date + * @param $default + * unix timestamp of default date + * @param $id + * id and name of datetimepicker (defaults to "datetimepicker") + * @param $pickdate + * true to show date picker (default) + * @param $picktime + * true to show time picker (default) + * @param $minfrom + * set minimum date from picker with id $minfrom (none by default) + * @param $maxfrom + * set maximum date from picker with id $maxfrom (none by default) + */ +function datetimesel($format, $min, $max, $default, $id = 'datetimepicker', $pickdate = true, $picktime = true, $minfrom = '', $maxfrom = '') { $o = ''; - if(strlen($f)) { - for($z = 0; $z < strlen($f); $z ++) { - if($f[$z] === 'y') { - - $o .= " "; - return $o; -} + $mindate = $min ? "new Date($min*1000)" : ''; + $maxdate = $max ? "new Date($max*1000)" : ''; + + $defaultDate = $default ? ", defaultDate: new Date($default*1000)" : ''; + $pickers = ''; + if(!$pickdate) $pickers .= 'pickDate: false,'; + if(!$picktime) $pickers .= 'pickTime: false,'; -function timesel($pre,$h,$m) { + $extra_js = ''; + if($minfrom != '') + $extra_js .= "\$('#$minfrom').on('dp.change',function (e) { \$('#$id').data('DateTimePicker').setMinDate(e.date); });"; - $o = ''; - $o .= " : "; + $o .= "
"; + $o .= ""; return $o; } - - - - - - - // implements "3 seconds ago" etc. // based on $posted_date, (UTC). // Results relative to current timezone @@ -516,4 +479,4 @@ function update_birthdays() { } } } -} \ No newline at end of file +} diff --git a/include/nav.php b/include/nav.php index ba817648b..f1f89db20 100644 --- a/include/nav.php +++ b/include/nav.php @@ -142,7 +142,7 @@ EOT; sprintf( t('%s - click to logout'), $observer['xchan_addr'])); } else { - $nav['loginmenu'][] = Array('rmagic',t('Remote login'),'',t('Click to authenticate to your home hub')); + $nav['loginmenu'][] = Array('rmagic',t('Remote authentication'),'',t('Click to authenticate to your home hub')); } /** -- cgit v1.2.3 From fd492386bf13152750c4db7306950d52b1105af1 Mon Sep 17 00:00:00 2001 From: friendica Date: Sun, 19 Oct 2014 17:31:10 -0700 Subject: Tried this once before but had to revert. Basically prevent a comment from being relayed more than once - as it's a huge drain on resources. But last time I tried this, wall-to-wall comments stopped getting relayed. This checkin should do the right thing in both conditions. --- include/zot.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/zot.php b/include/zot.php index 869bca668..e96eae10d 100644 --- a/include/zot.php +++ b/include/zot.php @@ -1476,11 +1476,13 @@ function process_delivery($sender,$arr,$deliveries,$relay,$public = false) { continue; } - $r = q("select id, edited from item where mid = '%s' and uid = %d limit 1", + $r = q("select id, edited, item_flags, mid, parent_mid from item where mid = '%s' and uid = %d limit 1", dbesc($arr['mid']), intval($channel['channel_id']) ); if($r) { + // We already have this post. + // Maybe it has been edited? $item_id = $r[0]['id']; if($arr['edited'] > $r[0]['edited']) { $arr['id'] = $r[0]['id']; @@ -1492,6 +1494,10 @@ function process_delivery($sender,$arr,$deliveries,$relay,$public = false) { } else { $result[] = array($d['hash'],'update ignored',$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>',$arr['mid']); + // We need this line to ensure wall-to-wall comments are relayed (by falling through to the relay bit), + // and at the same time not relay any other relayable posts more than once, because to do so is very wasteful. + if(! ($r[0]['item_flags'] & ITEM_ORIGIN)) + continue; } } else { -- cgit v1.2.3 From 8227be0ab0018866cb3a1a5d597b8712ba547d7f Mon Sep 17 00:00:00 2001 From: friendica Date: Sun, 19 Oct 2014 19:20:25 -0700 Subject: show true author of wall-to-wall comments to Diaspora viewers just like we did for wall-to-wall posts. --- include/bb2diaspora.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'include') diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php index 76708143b..9a87de5b2 100644 --- a/include/bb2diaspora.php +++ b/include/bb2diaspora.php @@ -286,6 +286,19 @@ function bb2diaspora_itemwallwall(&$item) { . '[url=' . $item['author']['xchan_url'] . ']' . $item['author']['xchan_name'] . '[/url]' . "\n\n" . $item['body']; } + + // We have to do something similar for wall-to-wall comments. ITEM_WALL|ITEM_ORIGIN indicates that it was posted on this site. + // Regular matrix comments may have one of these bits set, but not both. + + if(($item['mid'] != $item['parent_mid']) && ($item['author_xchan'] != $item['owner_xchan']) && ($item['item_flags'] & (ITEM_WALL|ITEM_ORIGIN)) && (is_array($item['author'])) && $item['author']['xchan_url'] && $item['author']['xchan_name'] && $item['author']['xchan_photo_m']) { + logger('bb2diaspora_itemwallwall: wall to wall comment',LOGGER_DEBUG); + // post will come across with the owner's identity. Throw a preamble onto the post to indicate the true author. + $item['body'] = "\n\n" + . '[img]' . $item['author']['xchan_photo_m'] . '[/img]' + . '[url=' . $item['author']['xchan_url'] . ']' . $item['author']['xchan_name'] . '[/url]' . "\n\n" + . $item['body']; + } + // $item['author'] might cause a surprise further down the line if it wasn't expected to be here. if(! $author_exists) -- cgit v1.2.3 From c909b8be060cb04479eba79232030e3da25410c6 Mon Sep 17 00:00:00 2001 From: friendica Date: Sun, 19 Oct 2014 21:41:38 -0700 Subject: don't auto-archive connections we can't poll. --- include/poller.php | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/poller.php b/include/poller.php index 2febaeb32..61298b0ab 100644 --- a/include/poller.php +++ b/include/poller.php @@ -254,7 +254,7 @@ function poller_run($argv, $argc){ ); - $contacts = q("SELECT abook_id, abook_flags, abook_updated, abook_connected, abook_closeness, abook_channel + $contacts = q("SELECT abook_id, abook_flags, abook_updated, abook_connected, abook_closeness, abook_xchan, abook_channel FROM abook LEFT JOIN account on abook_account = account_id where 1 $sql_extra AND (( abook_flags & %d ) OR ( abook_flags = %d )) @@ -310,12 +310,17 @@ function poller_run($argv, $argc){ // He's dead, Jim if(strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $c . " + 30 day")) > 0) { - $r = q("update abook set abook_flags = (abook_flags | %d) where abook_id = %d limit 1", - intval(ABOOK_FLAG_ARCHIVED), - intval($contact['abook_id']) + $n = q("select xchan_network from xchan where xchan_hash = '%s' limit 1", + dbesc($contact['abook_xchan']) ); - $update = false; - continue; + if($n && $n[0]['xchan_network'] == 'zot') { + $r = q("update abook set abook_flags = (abook_flags | %d) where abook_id = %d limit 1", + intval(ABOOK_FLAG_ARCHIVED), + intval($contact['abook_id']) + ); + $update = false; + continue; + } } if($contact['abook_flags'] & ABOOK_FLAG_ARCHIVED) { -- cgit v1.2.3 From 48b2eafcaaaa8cc05947c4b4b64c3e9daa78c2f4 Mon Sep 17 00:00:00 2001 From: Thomas Willingham Date: Mon, 20 Oct 2014 19:31:47 +0100 Subject: Prevent more than one instance of the poller running at a time. --- include/poller.php | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/poller.php b/include/poller.php index 61298b0ab..61d8b87cc 100644 --- a/include/poller.php +++ b/include/poller.php @@ -25,6 +25,15 @@ function poller_run($argv, $argc){ if(! $interval) $interval = ((get_config('system','delivery_interval') === false) ? 3 : intval(get_config('system','delivery_interval'))); + // Check for a logfile. If it exists, but is over an hour old, it's stale. Ignore it. + $lockfile = 'store/[data]/poller'; + if ((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600))) { + logger("poller: Already running"); + return; + } + + // Create a lockfile. Needs two vars, but $x doesn't need to contain anything. + file_put_contents($lockfile, $x); logger('poller: start'); @@ -254,7 +263,7 @@ function poller_run($argv, $argc){ ); - $contacts = q("SELECT abook_id, abook_flags, abook_updated, abook_connected, abook_closeness, abook_xchan, abook_channel + $contacts = q("SELECT abook_id, abook_flags, abook_updated, abook_connected, abook_closeness, abook_channel FROM abook LEFT JOIN account on abook_account = account_id where 1 $sql_extra AND (( abook_flags & %d ) OR ( abook_flags = %d )) @@ -310,17 +319,12 @@ function poller_run($argv, $argc){ // He's dead, Jim if(strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $c . " + 30 day")) > 0) { - $n = q("select xchan_network from xchan where xchan_hash = '%s' limit 1", - dbesc($contact['abook_xchan']) + $r = q("update abook set abook_flags = (abook_flags | %d) where abook_id = %d limit 1", + intval(ABOOK_FLAG_ARCHIVED), + intval($contact['abook_id']) ); - if($n && $n[0]['xchan_network'] == 'zot') { - $r = q("update abook set abook_flags = (abook_flags | %d) where abook_id = %d limit 1", - intval(ABOOK_FLAG_ARCHIVED), - intval($contact['abook_id']) - ); - $update = false; - continue; - } + $update = false; + continue; } if($contact['abook_flags'] & ABOOK_FLAG_ARCHIVED) { @@ -375,7 +379,10 @@ function poller_run($argv, $argc){ } } } - + + //All done - clear the lockfile + @unlink($lockfile); + return; } -- cgit v1.2.3 From 58431f948eb5e1d23548b537fdb92dea7d79e196 Mon Sep 17 00:00:00 2001 From: Thomas Willingham Date: Mon, 20 Oct 2014 19:35:02 +0100 Subject: Screwed up merge - put Mike's stuff back. --- include/poller.php | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/poller.php b/include/poller.php index 61d8b87cc..d18cb1ca6 100644 --- a/include/poller.php +++ b/include/poller.php @@ -263,7 +263,7 @@ function poller_run($argv, $argc){ ); - $contacts = q("SELECT abook_id, abook_flags, abook_updated, abook_connected, abook_closeness, abook_channel + $contacts = q("SELECT abook_id, abook_flags, abook_updated, abook_connected, abook_closeness, abook_xchan, abook_channel FROM abook LEFT JOIN account on abook_account = account_id where 1 $sql_extra AND (( abook_flags & %d ) OR ( abook_flags = %d )) @@ -319,12 +319,17 @@ function poller_run($argv, $argc){ // He's dead, Jim if(strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $c . " + 30 day")) > 0) { - $r = q("update abook set abook_flags = (abook_flags | %d) where abook_id = %d limit 1", - intval(ABOOK_FLAG_ARCHIVED), - intval($contact['abook_id']) + $n = q("select xchan_network from xchan where xchan_hash = '%s' limit 1", + dbesc($contact['abook_xchan']) ); - $update = false; - continue; + if($n && $n[0]['xchan_network'] == 'zot') { + $r = q("update abook set abook_flags = (abook_flags | %d) where abook_id = %d limit 1", + intval(ABOOK_FLAG_ARCHIVED), + intval($contact['abook_id']) + ); + $update = false; + continue; + } } if($contact['abook_flags'] & ABOOK_FLAG_ARCHIVED) { -- cgit v1.2.3 From cb15c73dae51c7001fa7277ef4d324645f72c5c3 Mon Sep 17 00:00:00 2001 From: friendica Date: Mon, 20 Oct 2014 16:47:58 -0700 Subject: move all theme initialisation to one place - just after calling module_init. Revert if there are serious issues, but please note the issues in as much detail as possible so we can work through them. --- include/RedDAV/RedBrowser.php | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/RedDAV/RedBrowser.php b/include/RedDAV/RedBrowser.php index 6ec5c978d..21ea76aed 100644 --- a/include/RedDAV/RedBrowser.php +++ b/include/RedDAV/RedBrowser.php @@ -259,6 +259,7 @@ class RedBrowser extends DAV\Browser\Plugin { $html .= $output; get_app()->page['content'] = $html; + load_pdl(get_app()); construct_page(get_app()); } -- cgit v1.2.3 From 577d84b883b52dde84c18c659a8c4674abe4e94e Mon Sep 17 00:00:00 2001 From: friendica Date: Mon, 20 Oct 2014 19:06:02 -0700 Subject: bb2diaspora wallwall comment - match both bits (ITEM_WALL|ITEM_ORIGIN) --- include/bb2diaspora.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php index 9a87de5b2..665fd4622 100644 --- a/include/bb2diaspora.php +++ b/include/bb2diaspora.php @@ -290,7 +290,7 @@ function bb2diaspora_itemwallwall(&$item) { // We have to do something similar for wall-to-wall comments. ITEM_WALL|ITEM_ORIGIN indicates that it was posted on this site. // Regular matrix comments may have one of these bits set, but not both. - if(($item['mid'] != $item['parent_mid']) && ($item['author_xchan'] != $item['owner_xchan']) && ($item['item_flags'] & (ITEM_WALL|ITEM_ORIGIN)) && (is_array($item['author'])) && $item['author']['xchan_url'] && $item['author']['xchan_name'] && $item['author']['xchan_photo_m']) { + if(($item['mid'] != $item['parent_mid']) && ($item['author_xchan'] != $item['owner_xchan']) && (($item['item_flags'] & (ITEM_WALL|ITEM_ORIGIN)) == (ITEM_WALL|ITEM_ORIGIN)) && (is_array($item['author'])) && $item['author']['xchan_url'] && $item['author']['xchan_name'] && $item['author']['xchan_photo_m']) { logger('bb2diaspora_itemwallwall: wall to wall comment',LOGGER_DEBUG); // post will come across with the owner's identity. Throw a preamble onto the post to indicate the true author. $item['body'] = "\n\n" -- cgit v1.2.3 From e8a7fb3d015b36af31312daf50739cf73f0f4368 Mon Sep 17 00:00:00 2001 From: friendica Date: Mon, 20 Oct 2014 21:15:29 -0700 Subject: strip out the Diaspora quoted reshare markers --- include/bb2diaspora.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php index 665fd4622..5663ce9ef 100644 --- a/include/bb2diaspora.php +++ b/include/bb2diaspora.php @@ -116,6 +116,8 @@ function diaspora_mention_callback($matches) { function diaspora2bb($s,$use_zrl = false) { + $s = str_replace(" \n>","",$s); + $s = html_entity_decode($s,ENT_COMPAT,'UTF-8'); // Too many new lines. So deactivated the following line -- cgit v1.2.3 From 1fb2de6d55779c853e25d38f5b93133a5414d72a Mon Sep 17 00:00:00 2001 From: Thomas Willingham Date: Tue, 21 Oct 2014 17:27:13 +0100 Subject: Typo --- include/poller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/poller.php b/include/poller.php index d18cb1ca6..f11618d37 100644 --- a/include/poller.php +++ b/include/poller.php @@ -25,7 +25,7 @@ function poller_run($argv, $argc){ if(! $interval) $interval = ((get_config('system','delivery_interval') === false) ? 3 : intval(get_config('system','delivery_interval'))); - // Check for a logfile. If it exists, but is over an hour old, it's stale. Ignore it. + // Check for a lockfile. If it exists, but is over an hour old, it's stale. Ignore it. $lockfile = 'store/[data]/poller'; if ((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600))) { logger("poller: Already running"); -- cgit v1.2.3 From ed7712cfbf9835368de79f8686954b536c12e4d1 Mon Sep 17 00:00:00 2001 From: friendica Date: Tue, 21 Oct 2014 16:33:35 -0700 Subject: private forum issues --- include/identity.php | 3 ++- include/items.php | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/identity.php b/include/identity.php index 07bfaebbd..8866b4811 100644 --- a/include/identity.php +++ b/include/identity.php @@ -389,7 +389,8 @@ function create_identity($arr) { dbesc( t('Friends') ) ); if($r) { - q("update channel set channel_allow_gid = '%s' where channel_id = %d limit 1", + q("update channel set channel_default_group = '%s', channel_allow_gid = '%s' where channel_id = %d limit 1", + dbesc($r[0]['hash']), dbesc('<' . $r[0]['hash'] . '>'), intval($newuid) ); diff --git a/include/items.php b/include/items.php index 40343d505..75eaecb20 100755 --- a/include/items.php +++ b/include/items.php @@ -98,6 +98,7 @@ function collect_recipients($item,&$private_envelope) { } } + // This is a somewhat expensive operation but important. // Don't send this item to anybody who isn't allowed to see it -- cgit v1.2.3 From d5edd89dd2bcfae198bb316c4f9be212937e9fa5 Mon Sep 17 00:00:00 2001 From: friendica Date: Tue, 21 Oct 2014 17:04:52 -0700 Subject: when removing a channel, check to see if there are any valid hublocs remaining before marking the xchan deleted. Issue #657 --- include/Contact.php | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/Contact.php b/include/Contact.php index 4440369dc..20e5e1a1e 100644 --- a/include/Contact.php +++ b/include/Contact.php @@ -245,11 +245,13 @@ function channel_remove($channel_id, $local = true, $unset_session=true) { intval($channel_id) ); + $r = q("update hubloc set hubloc_flags = (hubloc_flags | %d) where hubloc_hash = '%s'", intval(HUBLOC_FLAGS_DELETED), dbesc($channel['channel_hash']) ); + $r = q("update xchan set xchan_flags = (xchan_flags | %d) where xchan_hash = '%s'", intval(XCHAN_FLAGS_DELETED), dbesc($channel['channel_hash']) @@ -257,7 +259,6 @@ function channel_remove($channel_id, $local = true, $unset_session=true) { proc_run('php','include/notifier.php','purge_all',$channel_id); - } q("DELETE FROM `groups` WHERE `uid` = %d", intval($channel_id)); @@ -291,11 +292,23 @@ function channel_remove($channel_id, $local = true, $unset_session=true) { dbesc(z_root()) ); - $r = q("update xchan set xchan_flags = (xchan_flags | %d) where xchan_hash = '%s' ", - intval(XCHAN_FLAGS_DELETED), - dbesc($channel['channel_hash']) + // Do we have any valid hublocs remaining? + + $hublocs = 0; + + $r = q("select hubloc_id from hubloc where hubloc_hash = '%s' and not (hubloc_flags & %d)", + dbesc($channel['channel_hash']), + intval(HUBLOC_FLAGS_DELETED) ); + if($r) + $hublocs = count($r); + if(! $hublocs) { + $r = q("update xchan set xchan_flags = (xchan_flags | %d) where xchan_hash = '%s' ", + intval(XCHAN_FLAGS_DELETED), + dbesc($channel['channel_hash']) + ); + } proc_run('php','include/directory.php',$channel_id); -- cgit v1.2.3 From d7cb5c0436081214afefbd876a127173ebfa1b74 Mon Sep 17 00:00:00 2001 From: friendica Date: Wed, 22 Oct 2014 16:41:06 -0700 Subject: you've gotta' be on your toes to catch this bug... though it's been here for about 2 1/2 years and even survived a rewrite. Symptoms are that the archive widget only lists one month (the month when you first posted), and only if your first post was written between the 28th and 31st of whatever month that was. --- include/items.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/items.php b/include/items.php index 75eaecb20..a0c81f5ae 100755 --- a/include/items.php +++ b/include/items.php @@ -4131,7 +4131,7 @@ function list_post_dates($uid,$wall) { if(intval(substr($dnow,8)) > 28) $dnow = substr($dnow,0,8) . '28'; if(intval(substr($dthen,8)) > 28) - $dnow = substr($dthen,0,8) . '28'; + $dthen = substr($dthen,0,8) . '28'; $ret = array(); // Starting with the current month, get the first and last days of every @@ -4165,7 +4165,7 @@ function posted_dates($uid,$wall) { if(intval(substr($dnow,8)) > 28) $dnow = substr($dnow,0,8) . '28'; if(intval(substr($dthen,8)) > 28) - $dnow = substr($dthen,0,8) . '28'; + $dthen = substr($dthen,0,8) . '28'; $ret = array(); // Starting with the current month, get the first and last days of every -- cgit v1.2.3 From 902b5c52e5ca9359522f33bbecaf7f2f3c1ba90d Mon Sep 17 00:00:00 2001 From: friendica Date: Wed, 22 Oct 2014 18:14:21 -0700 Subject: backtrack on attribution for wall-to-wall comments - triggered too often and unnecessarily. --- include/bb2diaspora.php | 18 +++++++++++------- include/reddav.php | 4 ++-- 2 files changed, 13 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php index 5663ce9ef..4f37e5aa8 100644 --- a/include/bb2diaspora.php +++ b/include/bb2diaspora.php @@ -292,14 +292,18 @@ function bb2diaspora_itemwallwall(&$item) { // We have to do something similar for wall-to-wall comments. ITEM_WALL|ITEM_ORIGIN indicates that it was posted on this site. // Regular matrix comments may have one of these bits set, but not both. - if(($item['mid'] != $item['parent_mid']) && ($item['author_xchan'] != $item['owner_xchan']) && (($item['item_flags'] & (ITEM_WALL|ITEM_ORIGIN)) == (ITEM_WALL|ITEM_ORIGIN)) && (is_array($item['author'])) && $item['author']['xchan_url'] && $item['author']['xchan_name'] && $item['author']['xchan_photo_m']) { - logger('bb2diaspora_itemwallwall: wall to wall comment',LOGGER_DEBUG); + // Update: this is getting triggered way too often and unnecessarily. Commenting out until we find a better solution. + // It's not an easy problem. For now we'll live with the mis-attributions, as wall to wall comments are much less frequent + // than wall-to-wall posts. + +// if(($item['mid'] != $item['parent_mid']) && ($item['author_xchan'] != $item['owner_xchan']) && (($item['item_flags'] & (ITEM_WALL|ITEM_ORIGIN)) == (ITEM_WALL|ITEM_ORIGIN)) && (is_array($item['author'])) && $item['author']['xchan_url'] && $item['author']['xchan_name'] && $item['author']['xchan_photo_m']) { +// logger('bb2diaspora_itemwallwall: wall to wall comment',LOGGER_DEBUG); // post will come across with the owner's identity. Throw a preamble onto the post to indicate the true author. - $item['body'] = "\n\n" - . '[img]' . $item['author']['xchan_photo_m'] . '[/img]' - . '[url=' . $item['author']['xchan_url'] . ']' . $item['author']['xchan_name'] . '[/url]' . "\n\n" - . $item['body']; - } +// $item['body'] = "\n\n" +// . '[img]' . $item['author']['xchan_photo_m'] . '[/img]' +// . '[url=' . $item['author']['xchan_url'] . ']' . $item['author']['xchan_name'] . '[/url]' . "\n\n" +// . $item['body']; +// } // $item['author'] might cause a surprise further down the line if it wasn't expected to be here. diff --git a/include/reddav.php b/include/reddav.php index 86b3a00e4..c16e08e27 100644 --- a/include/reddav.php +++ b/include/reddav.php @@ -50,7 +50,7 @@ function RedChannelList(&$auth) { if ($r) { foreach ($r as $rr) { if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage')) { - logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DEBUG); + logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA); // @todo can't we drop '/cloud'? It gets stripped off anyway in RedDirectory $ret[] = new RedDAV\RedDirectory('/cloud/' . $rr['channel_address'], $auth); } @@ -188,7 +188,7 @@ function RedCollectionData($file, &$auth) { * @throw \Sabre\DAV\Exception\Forbidden */ function RedFileData($file, &$auth, $test = false) { - logger($file . (($test) ? ' (test mode) ' : ''), LOGGER_DEBUG); + logger($file . (($test) ? ' (test mode) ' : ''), LOGGER_DATA); $x = strpos($file, '/cloud'); if ($x === 0) { -- cgit v1.2.3 From 58c692e3897a7807fed23e2633496c4960f022ca Mon Sep 17 00:00:00 2001 From: friendica Date: Wed, 22 Oct 2014 20:39:49 -0700 Subject: improved wall-to-wall detection for comments so we can handle Diaspora signing and wall-to-wall attribution correctly. Do it at the point of submission. This also fixes a potential bug in yesterday's wall-to-wall permission setting, if it was a local comment to a remote post. --- include/items.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/items.php b/include/items.php index a0c81f5ae..e3526b0a5 100755 --- a/include/items.php +++ b/include/items.php @@ -2517,7 +2517,7 @@ function item_store_update($arr,$allow_exec = false) { return $ret; } -function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id) { +function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id, $walltowall = false) { // We won't be able to sign Diaspora comments for authenticated visitors // - we don't have their private key @@ -2527,7 +2527,16 @@ function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id) require_once('include/bb2diaspora.php'); $signed_body = bb2diaspora_itembody($datarray); - logger('mod_item: storing diaspora comment signature',LOGGER_DEBUG); + if($walltowall) { + logger('wall to wall comment',LOGGER_DEBUG); + // post will come across with the owner's identity. Throw a preamble onto the post to indicate the true author. + $signed_body = "\n\n" + . '[img]' . $datarray['author']['xchan_photo_m'] . '[/img]' + . '[url=' . $datarray['author']['xchan_url'] . ']' . $datarray['author']['xchan_name'] . '[/url]' . "\n\n" + . $signed_body; + } + + logger('storing diaspora comment signature',LOGGER_DEBUG); $diaspora_handle = $channel['channel_address'] . '@' . get_app()->get_hostname(); -- cgit v1.2.3 From 0ebfee8f87f73111b4de659ee5c97c12ad04b356 Mon Sep 17 00:00:00 2001 From: friendica Date: Thu, 23 Oct 2014 01:36:01 -0700 Subject: wrong permalink on remote events --- include/event.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/event.php b/include/event.php index 1fe6e6f7f..03ecaa0a7 100644 --- a/include/event.php +++ b/include/event.php @@ -400,8 +400,7 @@ function event_store_item($arr,$event) { } else { - $z = q("select * from channel where channel_hash = '%s' and channel_id = %d limit 1", - dbesc($event['event_xchan']), + $z = q("select * from channel where channel_id = %d limit 1", intval($arr['uid']) ); @@ -413,7 +412,7 @@ function event_store_item($arr,$event) { $item_arr['id'] = $item['id']; } else { - $wall = (($z) ? true : false); + $wall = (($z[0]['channel_hash'] == $event['event_xchan']) ? true : false); $item_flags = ITEM_THREAD_TOP; if($wall) { @@ -455,7 +454,14 @@ function event_store_item($arr,$event) { $item_arr['body'] = $prefix . format_event_bbcode($arr); - $item_arr['plink'] = z_root() . '/channel/' . $z[0]['channel_address'] . '/?f=&mid=' . $item_arr['mid']; + // if it's local send the permalink to the channel page. + // otherwise we'll fallback to /display/$message_id + + if($wall) + $item_arr['plink'] = z_root() . '/channel/' . $z[0]['channel_address'] . '/?f=&mid=' . $item_arr['mid']; + else + $item_arr['plink'] = z_root() . '/display/' . $item_arr['mid']; + $x = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($arr['event_xchan']) -- cgit v1.2.3 From f29c5a35f14f2a49b7c4a56fed577ebcf1010709 Mon Sep 17 00:00:00 2001 From: Thomas Willingham Date: Thu, 23 Oct 2014 21:50:53 +0100 Subject: Provide comment box for PERMS_AUTHED items. Presently only commentable from owners wall. --- include/items.php | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/items.php b/include/items.php index e3526b0a5..2805b9b21 100755 --- a/include/items.php +++ b/include/items.php @@ -214,6 +214,7 @@ function can_comment_on_post($observer_xchan,$item) { break; case 'any connections': case 'contacts': + case 'authenticated': case '': if(array_key_exists('owner',$item)) { if(($item['owner']['abook_xchan']) && ($item['owner']['abook_their_perms'] & PERMS_W_COMMENT)) -- cgit v1.2.3 From 1c4bbbd13e35e164c7da96674b3678bb1011b817 Mon Sep 17 00:00:00 2001 From: friendica Date: Thu, 23 Oct 2014 16:08:29 -0700 Subject: diaspora walltowall comment signature, force update. --- include/items.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/items.php b/include/items.php index 2805b9b21..8d46f64c1 100755 --- a/include/items.php +++ b/include/items.php @@ -2526,7 +2526,7 @@ function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id, // since Diaspora doesn't handle edits we can only do this for the original text and not update it. require_once('include/bb2diaspora.php'); - $signed_body = bb2diaspora_itembody($datarray); + $signed_body = bb2diaspora_itembody($datarray,$walltowall); if($walltowall) { logger('wall to wall comment',LOGGER_DEBUG); -- cgit v1.2.3 From 241bb3b94059ac4edfcc3b66e907dbf493dd8b4a Mon Sep 17 00:00:00 2001 From: friendica Date: Thu, 23 Oct 2014 19:33:47 -0700 Subject: API: xchan get/create --- include/api.php | 12 ++++++++ include/hubloc.php | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 91 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/api.php b/include/api.php index 8b52253dd..9fe2ef47d 100644 --- a/include/api.php +++ b/include/api.php @@ -621,7 +621,19 @@ require_once('include/items.php'); api_register_func('api/red/group','api_group', true); + function api_red_xchan(&$a,$type) { + if(api_user() === false) + return false; + require_once('include/hubloc.php'); + if($_SERVER['request_method'] === 'POST') { + $r = xchan_store($_REQUEST); + } + $r = xchan_fetch($_REQUEST); + json_return_and_die($r); + }; + api_register_func('api/red/xchan','api_red_xchan',true); + function api_statuses_mediap(&$a, $type) { if (api_user() === false) { diff --git a/include/hubloc.php b/include/hubloc.php index 04c29315a..df817329f 100644 --- a/include/hubloc.php +++ b/include/hubloc.php @@ -170,4 +170,82 @@ function hubloc_change_primary($hubloc) { return true; } - \ No newline at end of file + + +function xchan_store($arr) { + + if(! $arr['hash']) + $arr['hash'] = $arr['guid']; + if(! $arr['hash']) + return false; + + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($arr['hash']) + ); + if($r) + return true; + + if(! $arr['network']) + $arr['network'] = 'unknown'; + if(! $arr['name']) + $arr['name'] = 'unknown'; + if(! $arr['url']) + $arr['url'] = z_root(); + if(! $arr['photo']) + $arr['photo'] = get_default_profile_photo(); + + $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_guid_sig, xchan_pubkey, xchan_addr, xchan_url, xchan_connurl, xchan_follow, xchan_connpage, xchan_name, xchan_network, xchan_instance_url, xchan_flags, xchan_name_date ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s','%s','%s','%s',%d,'%s') ", + dbesc($arr['hash']), + dbesc($arr['guid']), + dbesc($arr['guid_sig']), + dbesc($arr['pubkey']), + dbesc($arr['address']), + dbesc($arr['url']), + dbesc($arr['connurl']), + dbesc($arr['follow']), + dbesc($arr['connpage']), + dbesc($arr['name']), + dbesc($arr['network']), + dbesc($arr['instance_url']), + intval($arr['flags']), + dbesc(datetime_convert()) + ); + if(! $r) + return $r; + + $photos = import_profile_photo($arr['photo'],$arr['hash']); + $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' limit 1", + dbesc(datetime_convert()), + dbesc($photos[0]), + dbesc($photos[1]), + dbesc($photos[2]), + dbesc($photos[3]), + dbesc($arr['hash']) + ); + return $r; + +} + + +function xchan_fetch($arr) { + + $key = ''; + if($arr['hash']) { + $key = 'xchan_hash'; + $v = $arr['hash']; + } + elseif($arr['guid']) { + $key = 'xchan_guid'; + $v = $arr['guid']; + } + elseif($arr['address']) { + $key = 'xchan_addr'; + $v = $arr['address']; + } + + if(! $key) + return false; + + $r = q("select * from xchan where $key = '$v'"); + return $r; +} \ No newline at end of file -- cgit v1.2.3 From f524fb1f20ec3edb0cf2c486d41f6bb65a60db6a Mon Sep 17 00:00:00 2001 From: friendica Date: Thu, 23 Oct 2014 19:41:42 -0700 Subject: generalise the output format of xchan_fetch so it matches the input format --- include/hubloc.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/hubloc.php b/include/hubloc.php index df817329f..0a1b51331 100644 --- a/include/hubloc.php +++ b/include/hubloc.php @@ -247,5 +247,15 @@ function xchan_fetch($arr) { return false; $r = q("select * from xchan where $key = '$v'"); - return $r; + if(! $r) + return false; + + $ret = array(); + foreach($r as $k => $v) { + if($k === 'xchan_addr') + $ret['address'] = $v; + else + $ret[str_replace('xchan_','',$k)] = $v; + } + return $ret; } \ No newline at end of file -- cgit v1.2.3 From 34781433c1fabd7a4992497da5ee475db0ada3a8 Mon Sep 17 00:00:00 2001 From: friendica Date: Thu, 23 Oct 2014 21:20:12 -0700 Subject: I'm speechless. This is just reckless. Set a context flag in text using a context trigger character which is likely to be present in that text already. Without escaping any previous instances of that character. Grrr. --- include/html2bbcode.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/html2bbcode.php b/include/html2bbcode.php index 6d6e6333b..9ffc85a82 100644 --- a/include/html2bbcode.php +++ b/include/html2bbcode.php @@ -16,7 +16,7 @@ function node2bbcode(&$doc, $oldnode, $attributes, $startbb, $endbb) function node2bbcodesub(&$doc, $oldnode, $attributes, $startbb, $endbb) { - $savestart = str_replace('$', '%', $startbb); + $savestart = str_replace('$', '\x01', $startbb); $replace = false; $xpath = new DomXPath($doc); @@ -37,7 +37,7 @@ function node2bbcodesub(&$doc, $oldnode, $attributes, $startbb, $endbb) foreach ($attributes as $attribute => $value) { - $startbb = str_replace('%'.++$i, '$1', $startbb); + $startbb = str_replace('\x01'.++$i, '$1', $startbb); if (strpos('*'.$startbb, '$1') > 0) { -- cgit v1.2.3 From 1845ddc4c3d3f729dde3905f0f87741ac3d3bf66 Mon Sep 17 00:00:00 2001 From: friendica Date: Fri, 24 Oct 2014 04:17:48 -0700 Subject: don't decrypt the message body more than once. --- include/bb2diaspora.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php index 4f37e5aa8..d094e33c2 100644 --- a/include/bb2diaspora.php +++ b/include/bb2diaspora.php @@ -340,8 +340,13 @@ function bb2diaspora_itembody($item,$force_update = false) { if(array_key_exists('item_flags',$item) && ($item['item_flags'] & ITEM_OBSCURED)) { $key = get_config('system','prvkey'); - $newitem['title'] = (($item['title']) ? crypto_unencapsulate(json_decode($item['title'],true),$key) : ''); - $newitem['body'] = (($item['body']) ? crypto_unencapsulate(json_decode($item['body'],true),$key) : ''); + $b = json_decode($item['title'],true); + // if called from diaspora_process_outbound, this decoding has already been done. + // Everything else that calls us will not yet be decoded. + if($b && is_array($b) && array_key_exists('iv',$b)) { + $newitem['title'] = (($item['title']) ? crypto_unencapsulate(json_decode($item['title'],true),$key) : ''); + $newitem['body'] = (($item['body']) ? crypto_unencapsulate(json_decode($item['body'],true),$key) : ''); + } } bb2diaspora_itemwallwall($newitem); -- cgit v1.2.3 From cf05266b15e49020c217107fd81896171d5ef26b Mon Sep 17 00:00:00 2001 From: friendica Date: Fri, 24 Oct 2014 14:04:32 -0700 Subject: should probably check the body since the title is only going to be rarely set. --- include/bb2diaspora.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php index d094e33c2..8a178d1ac 100644 --- a/include/bb2diaspora.php +++ b/include/bb2diaspora.php @@ -340,7 +340,7 @@ function bb2diaspora_itembody($item,$force_update = false) { if(array_key_exists('item_flags',$item) && ($item['item_flags'] & ITEM_OBSCURED)) { $key = get_config('system','prvkey'); - $b = json_decode($item['title'],true); + $b = json_decode($item['body'],true); // if called from diaspora_process_outbound, this decoding has already been done. // Everything else that calls us will not yet be decoded. if($b && is_array($b) && array_key_exists('iv',$b)) { -- cgit v1.2.3 From ce8a891682a7d8ceca71ec762063367744428a53 Mon Sep 17 00:00:00 2001 From: friendica Date: Fri, 24 Oct 2014 14:18:02 -0700 Subject: doh - this needs to be markdown, not bbcode --- include/items.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/items.php b/include/items.php index 8d46f64c1..41c211953 100755 --- a/include/items.php +++ b/include/items.php @@ -2532,8 +2532,8 @@ function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id, logger('wall to wall comment',LOGGER_DEBUG); // post will come across with the owner's identity. Throw a preamble onto the post to indicate the true author. $signed_body = "\n\n" - . '[img]' . $datarray['author']['xchan_photo_m'] . '[/img]' - . '[url=' . $datarray['author']['xchan_url'] . ']' . $datarray['author']['xchan_name'] . '[/url]' . "\n\n" + . '![' . $datarray['author']['xchan_name'] . '](' . $datarray['author']['xchan_photo_m'] . ')' + . '[' . $datarray['author']['xchan_name'] . '](' . $datarray['author']['xchan_url'] . ')' . "\n\n" . $signed_body; } -- cgit v1.2.3 From 655c3e1b4784f4bc37af1e1db0d7bcf313e71e66 Mon Sep 17 00:00:00 2001 From: friendica Date: Sun, 26 Oct 2014 19:32:12 -0700 Subject: put privacy role selector in settings page. Change visibility of various permissions items accordingly. --- include/permissions.php | 4 ++++ include/widgets.php | 13 ++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/permissions.php b/include/permissions.php index 61ac8aea3..4eead563f 100644 --- a/include/permissions.php +++ b/include/permissions.php @@ -734,6 +734,10 @@ function get_role_perms($role) { function role_selector($current) { + + if(! $current) + $current = 'custom'; + $roles = array( 'social' => array( t('Social Networking'), array('social' => t('Mostly Public'), 'social_restricted' => t('Restricted'), 'social_private' => t('Private'))), diff --git a/include/widgets.php b/include/widgets.php index 8905df59a..2e406aa77 100644 --- a/include/widgets.php +++ b/include/widgets.php @@ -430,6 +430,8 @@ function widget_settings_menu($arr) { // Retrieve the 'self' address book entry for use in the auto-permissions link + $role = get_pconfig(local_user(),'system','permissions_role'); + $abk = q("select abook_id from abook where abook_channel = %d and ( abook_flags & %d ) limit 1", intval(local_user()), intval(ABOOK_FLAG_SELF) @@ -487,14 +489,15 @@ function widget_settings_menu($arr) { 'selected' => '' ), - array( + ); + + if($role === false || $role === 'custom') { + $tabs[] = array( 'label' => t('Automatic Permissions (Advanced)'), 'url' => $a->get_baseurl(true) . '/connedit/' . $abook_self_id, 'selected' => '' - ), - - - ); + ); + } if(feature_enabled(local_user(),'premium_channel')) { $tabs[] = array( -- cgit v1.2.3 From be8a01618e5577e8324ebc59230165f233a20e89 Mon Sep 17 00:00:00 2001 From: friendica Date: Sun, 26 Oct 2014 21:56:56 -0700 Subject: turn down the preview logging. Haven't needed that level of detail recently. --- include/conversation.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/conversation.php b/include/conversation.php index b22b570a1..48fe8af60 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -827,8 +827,8 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ $threads = null; } - if($page_mode === 'preview') - logger('preview: ' . print_r($threads,true)); +// if($page_mode === 'preview') +// logger('preview: ' . print_r($threads,true)); // Do not un-comment if smarty3 is in use // logger('page_template: ' . $page_template); -- cgit v1.2.3 From 583b445bc02c988e808742b16196e0d80391b3cc Mon Sep 17 00:00:00 2001 From: friendica Date: Mon, 27 Oct 2014 16:19:30 -0700 Subject: add "repository" permissions role and make sure we have a sane "accept" default for the custom role. --- include/permissions.php | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/permissions.php b/include/permissions.php index 4eead563f..186ba32d8 100644 --- a/include/permissions.php +++ b/include/permissions.php @@ -460,6 +460,7 @@ function get_role_perms($role) { $ret['channel_w_chat'] = PERMS_CONTACTS; $ret['channel_a_delegate'] = 0; $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_w_storage'] = 0; $ret['channel_r_pages'] = PERMS_PUBLIC; $ret['channel_w_pages'] = 0; $ret['channel_a_republish'] = PERMS_SPECIFIC; @@ -492,6 +493,7 @@ function get_role_perms($role) { $ret['channel_w_chat'] = PERMS_CONTACTS; $ret['channel_a_delegate'] = 0; $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_w_storage'] = 0; $ret['channel_r_pages'] = PERMS_PUBLIC; $ret['channel_w_pages'] = 0; $ret['channel_a_republish'] = PERMS_SPECIFIC; @@ -524,6 +526,7 @@ function get_role_perms($role) { $ret['channel_w_chat'] = PERMS_SPECIFIC; $ret['channel_a_delegate'] = 0; $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_w_storage'] = 0; $ret['channel_r_pages'] = PERMS_PUBLIC; $ret['channel_w_pages'] = 0; $ret['channel_a_republish'] = PERMS_SPECIFIC; @@ -555,6 +558,7 @@ function get_role_perms($role) { $ret['channel_w_chat'] = PERMS_CONTACTS; $ret['channel_a_delegate'] = 0; $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_w_storage'] = 0; $ret['channel_r_pages'] = PERMS_PUBLIC; $ret['channel_w_pages'] = 0; $ret['channel_a_republish'] = PERMS_SPECIFIC; @@ -586,6 +590,7 @@ function get_role_perms($role) { $ret['channel_w_chat'] = PERMS_CONTACTS; $ret['channel_a_delegate'] = 0; $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_w_storage'] = 0; $ret['channel_r_pages'] = PERMS_PUBLIC; $ret['channel_w_pages'] = 0; $ret['channel_a_republish'] = PERMS_SPECIFIC; @@ -618,6 +623,7 @@ function get_role_perms($role) { $ret['channel_w_chat'] = PERMS_SPECIFIC; $ret['channel_a_delegate'] = 0; $ret['channel_r_storage'] = PERMS_CONTACTS; + $ret['channel_w_storage'] = 0; $ret['channel_r_pages'] = PERMS_CONTACTS; $ret['channel_w_pages'] = 0; $ret['channel_a_republish'] = PERMS_SPECIFIC; @@ -649,6 +655,7 @@ function get_role_perms($role) { $ret['channel_w_chat'] = PERMS_CONTACTS; $ret['channel_a_delegate'] = 0; $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_w_storage'] = 0; $ret['channel_r_pages'] = PERMS_PUBLIC; $ret['channel_w_pages'] = 0; $ret['channel_a_republish'] = PERMS_NETWORK; @@ -681,6 +688,7 @@ function get_role_perms($role) { $ret['channel_w_chat'] = PERMS_CONTACTS; $ret['channel_a_delegate'] = 0; $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_w_storage'] = 0; $ret['channel_r_pages'] = PERMS_PUBLIC; $ret['channel_w_pages'] = 0; $ret['channel_a_republish'] = PERMS_SPECIFIC; @@ -710,6 +718,7 @@ function get_role_perms($role) { $ret['channel_w_chat'] = 0; $ret['channel_a_delegate'] = 0; $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_w_storage'] = 0; $ret['channel_r_pages'] = PERMS_PUBLIC; $ret['channel_w_pages'] = 0; $ret['channel_a_republish'] = PERMS_SPECIFIC; @@ -717,6 +726,40 @@ function get_role_perms($role) { break; + case 'repository': + $ret['perms_auto'] = true; + $ret['default_collection'] = false; + $ret['directory_publish'] = true; + $ret['online'] = false; + $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT + |PERMS_R_STORAGE|PERMS_W_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE|PERMS_W_TAGWALL; + $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT + |PERMS_R_STORAGE|PERMS_W_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE|PERMS_W_TAGWALL; + $ret['channel_r_stream'] = PERMS_PUBLIC; + $ret['channel_r_profile'] = PERMS_PUBLIC; + $ret['channel_r_photos'] = PERMS_PUBLIC; + $ret['channel_r_abook'] = PERMS_PUBLIC; + $ret['channel_w_stream'] = PERMS_CONTACTS; + $ret['channel_w_wall'] = PERMS_CONTACTS; + $ret['channel_w_tagwall'] = PERMS_CONTACTS; + $ret['channel_w_comment'] = PERMS_CONTACTS; + $ret['channel_w_mail'] = PERMS_CONTACTS; + $ret['channel_w_photos'] = PERMS_CONTACTS; + $ret['channel_w_chat'] = PERMS_CONTACTS; + $ret['channel_a_delegate'] = 0; + $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_w_storage'] = PERMS_CONTACTS; + $ret['channel_r_pages'] = PERMS_PUBLIC; + $ret['channel_w_pages'] = PERMS_CONTACTS; + $ret['channel_a_republish'] = PERMS_SPECIFIC; + $ret['channel_w_like'] = PERMS_NETWORK; + + break; + + + default: break; @@ -745,8 +788,8 @@ function role_selector($current) { array('forum' => t('Mostly Public'), 'forum_restricted' => t('Restricted'), 'forum_private' => t('Private'))), 'feed' => array( t('Feed Republish'), array('feed' => t('Mostly Public'), 'feed_restricted' => t('Restricted'))), - 'soapbox' => array( t('Celebrity/Soapbox'), - array('soapbox' => t('Mostly Public'))), + 'special' => array( t('Special Purpose'), + array('soapbox' => t('Celebrity/Soapbox'), 'repository' => t('Group Repository'))), 'other' => array( t('Other'), array('custom' => t('Custom/Expert Mode')))); $o = '