Merge remote branch 'upstream/master'

This commit is contained in:
habeascodice 2014-10-15 17:26:07 -07:00
commit cf58122b29
26 changed files with 490 additions and 280 deletions

View File

@ -48,7 +48,7 @@ define ( 'RED_PLATFORM', 'redmatrix' );
define ( 'RED_VERSION', trim(file_get_contents('version.inc')) . 'R');
define ( 'ZOT_REVISION', 1 );
define ( 'DB_UPDATE_VERSION', 1129 );
define ( 'DB_UPDATE_VERSION', 1130 );
define ( 'EOL', '<br />' . "\r\n" );
define ( 'ATOM_TIME', 'Y-m-d\TH:i:s\Z' );

View File

@ -98,3 +98,6 @@ This document assumes you're an administrator.
Logfile to use for logging auth errors. Used to plug in to server
side software such as fail2ban. Auth failures are still logged to
the main logs as well.
[b]system > hide_in_statistics[/b]
Tell the red statistics servers to completely hide this hub in hub lists.

View File

@ -55,7 +55,7 @@ server {
ssl_certificate /etc/nginx/ssl/red.example.net.chain.pem;
ssl_certificate_key /etc/nginx/ssl/example.net.key;
ssl_session_timeout 5m;
ssl_protocols SSLv3 TLSv1;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv3:+EXP;
ssl_prefer_server_ciphers on;

View File

@ -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);
}
}

View File

@ -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)) {

View File

@ -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.
*/

View File

@ -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.');

View File

@ -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',
'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',
// 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',
// 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',
// 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',
// 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',
// 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',
// 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,59 +845,82 @@ 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;
}
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)
);
$filename = "";
if($r) {
foreach($r as $rr) {
$filename = $rr['filename'];
}
}
return $filename;
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 filename FROM attach WHERE uid = %d AND hash = '%s' LIMIT 1",
intval($channel_id),
dbesc($attachHash)
);
$filename = '';
if ($r) {
$filename = $r[0]['filename'];
}
return $filename;
}
/**
*
@ -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;
}

View File

@ -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)

View File

@ -113,4 +113,61 @@ 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)) {
logger('no hubloc');
return false;
}
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
$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) {
logger('xchan not found');
return false;
}
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'],'@'));
$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'),
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;
}

View File

@ -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');

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
}
}
@ -1832,17 +1838,28 @@ 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'])
);
// 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;
}
elseif($absolute) {
// Absolute sync - make sure the current primary is correctly reflected in the xchan
$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']))) {
$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'])
@ -1884,6 +1901,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.

View File

@ -1,6 +1,6 @@
<?php
define( 'UPDATE_VERSION' , 1129 );
define( 'UPDATE_VERSION' , 1130 );
/**
*
@ -1457,3 +1457,10 @@ function update_r1128() {
}
function update_r1129() {
$r = q("update hubloc set hubloc_network = 'zot' where hubloc_network = ''");
if($r)
return UPDATE_SUCCESS;
return UPDATE_FAILED;
}

View File

@ -1,31 +0,0 @@
<?php /** @file */
/**
Placeholder file at present. This is going to involve a bit of work.
This file will deal with the deletion of channels and management of hublocs.
We need to provide the following functionality:
- Delete my account and all channels from the entire network
- Delete my account and all channels from this server
- Delete a channel from the entire network
- Delete a channel from this server
- List all hub locations for this channel
- Remove this/some hub location from this channel
- promote this/some hub location to primary
- Remove hub location 'xyz' from this channel, (this should possibly only be allowed if that hub has been down for a period of time)
- Some of these actions should probably require email verification
*/

View File

@ -1,18 +1,26 @@
<?php
/**
* @file mod/filestorage.php
*
*/
require_once('include/attach.php');
/**
*
* @param object &$a
*/
function filestorage_post(&$a) {
$channel_id = ((x($_POST,'uid')) ? intval($_POST['uid']) : 0);
$channel_id = ((x($_POST, 'uid')) ? intval($_POST['uid']) : 0);
if((! $channel_id) || (! local_user()) || ($channel_id != local_user())) {
notice( t('Permission denied.') . EOL);
return;
}
$recurse = ((x($_POST,'recurse')) ? intval($_POST['recurse']) : 0);
$resource = ((x($_POST,'filehash')) ? notags($_POST['filehash']) : '');
$recurse = ((x($_POST, 'recurse')) ? intval($_POST['recurse']) : 0);
$resource = ((x($_POST, 'filehash')) ? notags($_POST['filehash']) : '');
if(! $resource) {
notice(t('Item not found.') . EOL);
@ -24,11 +32,11 @@ function filestorage_post(&$a) {
$str_group_deny = perms2str($_REQUEST['group_deny']);
$str_contact_deny = perms2str($_REQUEST['contact_deny']);
attach_change_permissions($channel_id,$resource,$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny,$recurse = false);
attach_change_permissions($channel_id, $resource, $str_contact_allow, $str_group_allow, $str_contact_deny,$str_group_deny, $recurse = false);
//Build directory tree and redirect
$channel = $a->get_channel();
$cloudPath = get_parent_cloudpath($channel_id, $channel['channel_address'], $resource) ;
$cloudPath = get_parent_cloudpath($channel_id, $channel['channel_address'], $resource);
goaway($cloudPath);
}
@ -53,15 +61,15 @@ function filestorage_content(&$a) {
$observer = $a->get_observer();
$ob_hash = (($observer) ? $observer['xchan_hash'] : '');
$perms = get_all_perms($owner,$ob_hash);
$perms = get_all_perms($owner, $ob_hash);
if(! $perms['view_storage']) {
notice( t('Permission denied.') . EOL);
return;
}
// Since we have ACL'd files in the wild, but don't have ACL here yet, we
// need to return for anyone other than the owner, despite the perms check for now.
// Since we have ACL'd files in the wild, but don't have ACL here yet, we
// need to return for anyone other than the owner, despite the perms check for now.
$is_owner = (((local_user()) && ($owner == local_user())) ? true : false);
if(! $is_owner) {
@ -69,7 +77,6 @@ function filestorage_content(&$a) {
return;
}
if(argc() > 3 && argv(3) === 'delete') {
if(! $perms['write_storage']) {
notice( t('Permission denied.') . EOL);
@ -77,7 +84,7 @@ function filestorage_content(&$a) {
}
$file = intval(argv(2));
$r = q("select hash from attach where id = %d and uid = %d limit 1",
$r = q("SELECT hash FROM attach WHERE id = %d AND uid = %d LIMIT 1",
dbesc($file),
intval($owner)
);
@ -86,11 +93,15 @@ function filestorage_content(&$a) {
goaway(z_root() . '/cloud/' . $which);
}
attach_delete($owner,$r[0]['hash']);
goaway(z_root() . '/cloud/' . $which);
}
$f = $r[0];
$channel = $a->get_channel();
$parentpath = get_parent_cloudpath($channel['channel_id'], $channel['channel_address'], $f['hash']);
attach_delete($owner, $f['hash']);
goaway($parentpath);
}
if(argc() > 3 && argv(3) === 'edit') {
require_once('include/acl_selectors.php');
@ -106,18 +117,16 @@ function filestorage_content(&$a) {
);
$f = $r[0];
$channel = $a->get_channel();
$cloudpath = get_cloudpath($f) . (($f['flags'] & ATTACH_FLAG_DIR) ? '?f=&davguest=1' : '');
$parentpath = get_parent_cloudpath($channel['channel_id'], $channel['channel_address'], $f['hash']);
$aclselect_e = populate_acl($f,false);
$aclselect_e = populate_acl($f, false);
$is_a_dir = (($f['flags'] & ATTACH_FLAG_DIR) ? true : false);
$lockstate = (($f['allow_cid'] || $f['allow_gid'] || $f['deny_cid'] || $f['deny_gid']) ? 'lock' : 'unlock');
$o = replace_macros(get_markup_template('attach_edit.tpl'), array(
'$header' => t('Edit file permissions'),
'$file' => $f,
@ -135,12 +144,10 @@ function filestorage_content(&$a) {
'$cpdesc' => t('Copy/paste this code to attach file to a post'),
'$cpldesc' => t('Copy/paste this URL to link file from a web page'),
'$submit' => t('Submit')
));
return $o;
}
}
goaway(z_root() . '/cloud/' . $which);
}

View File

@ -344,7 +344,7 @@ function import_post(&$a) {
unset($group['id']);
$group['uid'] = $channel['channel_id'];
dbesc_array($group);
$r = dbq("INSERT INTO group (`"
$r = dbq("INSERT INTO groups (`"
. implode("`, `", array_keys($group))
. "`) VALUES ('"
. implode("', '", array_values($group))

90
mod/locs.php Normal file
View File

@ -0,0 +1,90 @@
<?php /** @file */
/**
Placeholder file at present. This is going to involve a bit of work.
This file will deal with the deletion of channels and management of hublocs.
We need to provide the following functionality:
- Delete my account and all channels from the entire network
- Delete my account and all channels from this server
- Delete a channel from the entire network
- Delete a channel from this server
- List all hub locations for this channel
- Remove this/some hub location from this channel
- promote this/some hub location to primary
- Remove hub location 'xyz' from this channel, (this should possibly only be allowed if that hub has been down for a period of time)
- Some of these actions should probably require email verification
*/
function locs_post(&$a) {
if(! local_user())
return;
$channel = $a->get_channel();
if($_REQUEST['primary']) {
$hubloc_id = intval($_REQUEST['primary']);
if($hubloc_id) {
$r = q("select hubloc_id from hubloc where hubloc_id = %d and hubloc_hash = '%s' limit 1",
intval($hubloc_id),
dbesc($channel['channel_hash'])
);
if(! $r) {
notice( t('Location not found.') . EOL);
return;
}
$r = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d) where (hubloc_flags & %d) and hubloc_hash = '%s' ",
intval(HUBLOC_FLAGS_PRIMARY),
intval(HUBLOC_FLAGS_PRIMARY),
dbesc($channel['channel_hash'])
);
$r = q("update hubloc set hubloc_flags = (hubloc_flags & %d) where hubloc_id = %d and hubloc_hash = '%s' limit 1",
intval(HUBLOC_FLAGS_PRIMARY),
intval($hubloc_id),
dbesc($channel['channel_hash'])
);
proc_run('php','include/notifier.php','location',$channel['channel_id']);
return;
}
}
if($_REQUEST['drop']) {
$hubloc_id = intval($_REQUEST['drop']);
if($hubloc_id) {
$r = q("select hubloc_id, hubloc_flags from hubloc where hubloc_id = %d and hubloc_url != '%s' and hubloc_hash = '%s' limit 1",
intval($hubloc_id),
dbesc(z_root()),
dbesc($channel['channel_hash'])
);
if(! $r) {
notice( t('Location not found.') . EOL);
return;
}
if($r[0]['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY) {
notice( t('Primary location cannot be removed.') . EOL);
return;
}
$r = q("update hubloc set hubloc_flags = (hubloc_flags & %d) where hubloc_id = %d and hubloc_hash = '%s' limit 1",
intval(HUBLOC_FLAGS_DELETED),
intval($hubloc_id),
dbesc($channel['channel_hash'])
);
proc_run('php','include/notifier.php','location',$channel['channel_id']);
return;
}
}
}

View File

@ -999,7 +999,7 @@ function photos_content(&$a) {
$comments = '';
if(! count($r)) {
if($can_post || $can_comment) {
$comments .= replace_macros($cmnt_tpl,array(
$commentbox = replace_macros($cmnt_tpl,array(
'$return_path' => '',
'$mode' => 'photos',
'$jsreload' => $return_url,
@ -1070,7 +1070,7 @@ function photos_content(&$a) {
$body_e = prepare_text($item['body'],$item['mimetype']);
$comments .= replace_macros($template,array(
'$id' => $item['item_id'],
'$id' => $item['id'],
'$mode' => 'photos',
'$profile_url' => $profile_link,
'$name' => $name_e,
@ -1079,7 +1079,7 @@ function photos_content(&$a) {
'$title' => $title_e,
'$body' => $body_e,
'$ago' => relative_date($item['created']),
'$indent' => (($item['parent'] != $item['item_id']) ? ' comment' : ''),
'$indent' => (($item['parent'] != $item['id']) ? ' comment' : ''),
'$drop' => $drop,
'$comment' => $comment
));
@ -1087,7 +1087,7 @@ function photos_content(&$a) {
}
if($can_post || $can_comment) {
$comments .= replace_macros($cmnt_tpl,array(
$commentbox = replace_macros($cmnt_tpl,array(
'$return_path' => '',
'$jsreload' => $return_url,
'$type' => 'wall-comment',
@ -1129,6 +1129,7 @@ function photos_content(&$a) {
'$like' => $like_e,
'$dislike' => $dislike_e,
'$comments' => $comments,
'$commentbox' => $commentbox,
'$paginate' => $paginate,
));

View File

@ -1 +1 @@
2014-10-13.827
2014-10-14.828

View File

@ -81,13 +81,8 @@
/* group */
input.group-edit-checkbox {
margin: unset;
height: 1em;
width: 1em;
}
a.group-edit-link {
a.group-edit-tool {
z-index: 1;
}

View File

@ -986,6 +986,7 @@ function updateConvItems(mode,data) {
$('body').css('cursor', 'wait');
$.get('contactgroup/' + gid + '/' + cid, function(data) {
$('body').css('cursor', 'auto');
$('#group-' + gid).toggleClass('icon-check icon-check-empty');
});
}

View File

@ -5,16 +5,12 @@
{{foreach $groups as $group}}
<li>
{{if $group.cid}}
<a class="pull-right group-edit-link">
<input type="checkbox"
class="{{if $group.selected}}ticked{{else}}unticked {{/if}} group-edit-checkbox"
onclick="contactgroupChangeMember('{{$group.id}}','{{$group.enc_cid}}');return true;"
{{if $group.ismember}}checked="checked"{{/if}}
/>
<a class="pull-right group-edit-tool fakelink" onclick="contactgroupChangeMember('{{$group.id}}','{{$group.enc_cid}}'); return true;"/>
<i id="group-{{$group.id}}" class="{{if $group.ismember}}icon-check{{else}}icon-check-empty{{/if}}"></i>
</a>
{{/if}}
{{if $group.edit}}
<a class="pull-right group-edit-link" href="{{$group.edit.href}}" title="{{$edittext}}"><i class="group-edit-icon icon-pencil"></i></a>
<a class="pull-right group-edit-tool" href="{{$group.edit.href}}" title="{{$edittext}}"><i class="group-edit-icon icon-pencil"></i></a>
{{/if}}
<a{{if $group.selected}} class="group-selected"{{/if}} href="{{$group.href}}">{{$group.text}}</a>
</li>

View File

@ -1,22 +1,27 @@
<div class="wall-item-outside-wrapper{{$indent}}" id="wall-item-outside-wrapper-{{$id}}" >
<div class="wall-item-photo-wrapper" id="wall-item-photo-wrapper-{{$id}}" >
<a href="{{$profile_url}}" title="View {{$name}}'s profile" class="wall-item-photo-link" id="wall-item-photo-link-{{$id}}">
<img src="{{$thumb}}" class="wall-item-photo" id="wall-item-photo-{{$id}}" style="height: 80px; width: 80px;" alt="{{$name}}" /></a>
</div>
<div class="wall-item-outside-wrapper {{$indent}}" id="wall-item-outside-wrapper-{{$id}}" >
<div class="wall-item-content-wrapper {{$indent}}" id="wall-item-content-wrapper-{{$id}}" style="clear:both;">
<div class="wall-item-info" id="wall-item-info-{{$item.id}}" >
<div class="wall-item-photo-wrapper" id="wall-item-photo-wrapper-{{$id}}" >
<a href="{{$profile_url}}" title="View {{$name}}'s profile" class="wall-item-photo-link" id="wall-item-photo-link-{{$id}}">
<img src="{{$thumb}}" class="wall-item-photo" id="wall-item-photo-{{$id}}" style="height: 80px; width: 80px;" alt="{{$name}}" /></a>
</div>
</div>
<div class="wall-item-wrapper" id="wall-item-wrapper-{{$id}}" >
<div class="wall-item-author">
<a href="{{$profile_url}}" title="View {{$name}}'s profile" class="wall-item-name-link"><span class="wall-item-name" id="wall-item-name-{{$id}}" >{{$name}}</span></a>
</div>
<div class="wall-item-ago" id="wall-item-ago-{{$id}}">{{$ago}}</div>
</div>
<div class="wall-item-content" id="wall-item-content-{{$id}}" >
<div class="wall-item-title" id="wall-item-title-{{$id}}">{{$title}}</div>
<div class="wall-item-body" id="wall-item-body-{{$id}}" >{{$body}}</div>
</div>
{{$drop}}
<div class="wall-item-wrapper-end"></div>
<div class="wall-item-wrapper" id="wall-item-wrapper-{{$id}}" >
<a href="{{$profile_url}}" title="View {{$name}}'s profile" class="wall-item-name-link"><span class="wall-item-name" id="wall-item-name-{{$id}}" >{{$name}}</span></a>
<div class="wall-item-ago" id="wall-item-ago-{{$id}}">{{$ago}}</div>
</div>
<div class="wall-item-content" id="wall-item-content-{{$id}}" >
<div class="wall-item-title" id="wall-item-title-{{$id}}">{{$title}}</div>
<div class="wall-item-body" id="wall-item-body-{{$id}}" >{{$body}}</div>
</div>
{{$drop}}
<div class="wall-item-wrapper-end"></div>
<div class="wall-item-comment-separator"></div>
{{$comment}}
{{$comment}}
<div class="wall-item-outside-wrapper-end{{$indent}}" ></div>
<div class="wall-item-outside-wrapper-end{{$indent}}" ></div>
</div>
</div>

View File

@ -92,6 +92,10 @@
{{$comments}}
<div class="wall-item-comment-wrapper{{if $comments}} wall-item-comment-wrapper-wc{{/if}}" >
{{$commentbox}}
</div>
</div>
{{if $nextlink}}<div id="photo-next-link"><a href="{{$nextlink.0}}"><i class="icon-forward photo-icons"></i></a></div>{{/if}}