aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/Contact.php26
-rw-r--r--include/ItemObject.php1
-rw-r--r--include/attach.php133
-rw-r--r--include/bbcode.php56
-rw-r--r--include/comanche.php13
-rw-r--r--include/conversation.php27
-rw-r--r--include/dir_fns.php16
-rw-r--r--include/directory.php16
-rw-r--r--include/enotify.php2
-rw-r--r--include/features.php5
-rw-r--r--include/group.php7
-rwxr-xr-xinclude/items.php21
-rw-r--r--include/js_strings.php16
-rw-r--r--include/message.php13
-rwxr-xr-xinclude/oembed.php1
-rw-r--r--include/poller.php35
-rw-r--r--include/reddav.php196
-rw-r--r--include/taxonomy.php10
-rwxr-xr-xinclude/text.php4
-rw-r--r--include/widgets.php34
-rw-r--r--include/zot.php28
21 files changed, 609 insertions, 51 deletions
diff --git a/include/Contact.php b/include/Contact.php
index 46c84aab6..de4ac6ff7 100644
--- a/include/Contact.php
+++ b/include/Contact.php
@@ -216,11 +216,12 @@ function channel_remove($channel_id, $local = true) {
// FIXME notify all contacts
- $r = q("update channel set channel_pageflags = (channel_pageflags | %d), channel_r_stream = 0, channel_r_profile = 0,
+ $r = q("update channel set channel_deleted = '%s', channel_pageflags = (channel_pageflags | %d), channel_r_stream = 0, channel_r_profile = 0,
channel_r_photos = 0, channel_r_abook = 0, channel_w_stream = 0, channel_w_wall = 0, channel_w_tagwall = 0,
channel_w_comment = 0, channel_w_mail = 0, channel_w_photos = 0, channel_w_chat = 0, channel_a_delegate = 0,
channel_r_storage = 0, channel_w_storage = 0, channel_r_pages = 0, channel_w_pages = 0, channel_a_republish = 0
where channel_id = %d limit 1",
+ dbesc(datetime_convert()),
intval(PAGE_REMOVED),
intval($channel_id)
);
@@ -230,6 +231,11 @@ function channel_remove($channel_id, $local = true) {
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'])
+ );
+
proc_run('php','include/notifier.php','purge_all',$channel_id);
@@ -248,13 +254,25 @@ function channel_remove($channel_id, $local = true) {
q("DELETE FROM `pconfig` WHERE `uid` = %d", intval($channel_id));
q("DELETE FROM `spam` WHERE `uid` = %d", intval($channel_id));
- // We also need a timestamp in the channel DB so we know when to remove the entry.
-
- $r = q("update channel set channel_pageflags = (channel_pageflags | %d) where channel_id = %d limit 1",
+ $r = q("update channel set channel_deleted = '%s', channel_pageflags = (channel_pageflags | %d) where channel_id = %d limit 1",
+ dbesc(datetime_convert()),
intval(PAGE_REMOVED),
intval($channel_id)
);
+ $r = q("update hubloc set hubloc_flags = hubloc_flags | %d where hubloc_hash = '%s' and hubloc_url = '%s' ",
+ intval(HUBLOC_FLAGS_DELETED),
+ dbesc($channel['channel_hash']),
+ 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'])
+ );
+
+
+ proc_run('php','include/directory.php',$channel_id);
if($channel_id == local_user()) {
unset($_SESSION['authenticated']);
diff --git a/include/ItemObject.php b/include/ItemObject.php
index 59b4538df..818f8c0b2 100644
--- a/include/ItemObject.php
+++ b/include/ItemObject.php
@@ -216,6 +216,7 @@ class Item extends BaseObject {
'str_app' => sprintf( t(' from %s'), $item['app']),
'isotime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'c'),
'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'r'),
+ 'editedtime' => (($item['edited'] != $item['created']) ? sprintf( t('last edited: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['edited'], 'r')) : ''),
'lock' => $lock,
'verified' => $verified,
'unverified' => $unverified,
diff --git a/include/attach.php b/include/attach.php
index da08154c6..0c748cba6 100644
--- a/include/attach.php
+++ b/include/attach.php
@@ -500,4 +500,137 @@ function z_readdir($channel_id,$observer_hash,$pathname, $parent_hash = '') {
$ret['success'] = true;
$ret['data'] = $r;
return $ret;
+}
+
+
+/**
+ * @function attach_mkdir($channel,$observer_hash,$arr);
+ *
+ * Create directory
+ *
+ * @param $channel channel array of owner
+ * @param $observer_hash hash of current observer
+ * @param $arr parameter array to fulfil request
+ *
+ * Required:
+ * $arr['filename']
+ * $arr['folder'] // hash of parent directory, empty string for root directory
+ *
+ * Optional:
+ * $arr['hash'] // precumputed hash for this node
+ * $arr['allow_cid']
+ * $arr['allow_gid']
+ * $arr['deny_cid']
+ * $arr['deny_gid']
+ */
+
+function attach_mkdir($channel,$observer_hash,$arr = null) {
+
+ $ret = array('success' => false);
+ $channel_id = $channel['channel_id'];
+ $sql_options = '';
+
+ $basepath = 'store/' . $channel['channel_address'];
+ if(! is_dir($basepath))
+ @mkdir($basepath,STORAGE_DEFAULT_PERMISSIONS,true);
+
+
+ if(! perm_is_allowed($channel_id, get_observer_hash(),'write_storage')) {
+ $ret['message'] = t('Permission denied.');
+ return $ret;
+ }
+
+ if(! $arr['filename']) {
+ $ret['message'] = t('Empty pathname');
+ return $ret;
+ }
+
+
+ $arr['hash'] = (($arr['hash']) ? $arr['hash'] : random_string());
+
+
+ // Check for duplicate name.
+ // Check both the filename and the hash as we will be making use of both.
+
+ $r = q("select hash from attach where ( filename = '%s' or hash = '%s' ) and folder = '%s' and uid = %d limit 1",
+ dbesc($arr['filename']),
+ dbesc($arr['hash']),
+ dbesc($arr['folder']),
+ intval($channel['channel_id'])
+ );
+ if($r) {
+ $ret['message'] = t('duplicate filename or path');
+ return $ret;
+ }
+
+ if($arr['folder']) {
+
+ // Walk the directory tree from parent back to root to make sure the parent is valid and name is unique and we
+ // have permission to see this path. This implies the root directory itself is public since we won't have permissions
+ // set on the psuedo-directory. We can however set permissions for anything and everything contained within it.
+
+ $lpath = '';
+ $lfile = $arr['folder'];
+ $sql_options = permissions_sql($channel);
+
+ do {
+ $r = q("select filename, hash, flags, folder from attach where uid = %d and hash = '%s' and ( flags & %d )
+ $sql_options limit 1",
+ intval($channel['channel_id']),
+ dbesc($lfile),
+ intval(ATTACH_FLAG_DIR)
+ );
+ if(! $r) {
+ $ret['message'] = t('Path not found.');
+ return $ret;
+ }
+ if($lfile)
+ $lpath = $r[0]['hash'] . '/' . $lpath;
+ $lfile = $r[0]['folder'];
+ } while ( ($r[0]['folder']) && ($r[0]['flags'] & ATTACH_FLAG_DIR)) ;
+ $path = $basepath . '/' . $lpath;
+
+ }
+ else
+ $path = $basepath . '/';
+
+ $path .= $arr['hash'];
+
+ $created = datetime_convert();
+
+ $r = q("INSERT INTO attach ( aid, uid, hash, filename, filetype, filesize, revision, folder, flags, data, created, edited, allow_cid, allow_gid, deny_cid, deny_gid )
+ VALUES ( %d, %d, '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ",
+ intval($channel['channel_account_id']),
+ intval($channel_id),
+ dbesc($arr['hash']),
+ dbesc($arr['filename']),
+ dbesc('multipart/mixed'),
+ intval(0),
+ intval(0),
+ dbesc($arr['folder']),
+ intval(ATTACH_FLAG_DIR),
+ dbesc(''),
+ dbesc($created),
+ dbesc($created),
+ dbesc(($arr && array_key_exists('allow_cid',$arr)) ? $arr['allow_cid'] : ''),
+ dbesc(($arr && array_key_exists('allow_gid',$arr)) ? $arr['allow_gid'] : ''),
+ dbesc(($arr && array_key_exists('deny_cid',$arr)) ? $arr['deny_cid'] : ''),
+ dbesc(($arr && array_key_exists('deny_gid',$arr)) ? $arr['deny_gid'] : '')
+ );
+
+ if($r) {
+ if(mkdir($path,STORAGE_DEFAULT_PERMISSIONS)) {
+ $ret['success'] = true;
+ $ret['data'] = $arr;
+ }
+ else {
+ logger('attach_mkdir: ' . mkdir . ' ' . $path . 'failed.');
+ $ret['message'] = t('mkdir failed.');
+ }
+ }
+ else
+ $ret['message'] = t('database storage failed.');
+
+ return $ret;
+
} \ No newline at end of file
diff --git a/include/bbcode.php b/include/bbcode.php
index 756d73aba..271cace73 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -2,7 +2,7 @@
require_once("include/oembed.php");
require_once('include/event.php');
-
+require_once('include/zot.php');
function tryoembed($match) {
@@ -99,6 +99,38 @@ function bb_replace_images($body, $images) {
}}
+
+function bb_parse_crypt($match) {
+
+ $attributes = $match[1];
+
+ $algorithm = "";
+ preg_match("/alg='(.*?)'/ism", $attributes, $matches);
+ if ($matches[1] != "")
+ $algorithm = html_entity_decode($matches[1],ENT_QUOTES,'UTF-8');
+
+ preg_match("/alg=\&quot\;(.*?)\&quot\;/ism", $attributes, $matches);
+ if ($matches[1] != "")
+ $algorithm = html_entity_decode($matches[1],ENT_QUOTES,'UTF-8');
+
+ $hint = "";
+ preg_match("/hint='(.*?)'/ism", $attributes, $matches);
+ if ($matches[1] != "")
+ $hint = html_entity_decode($matches[1],ENT_QUOTES,'UTF-8');
+ preg_match("/hint=\&quot\;(.*?)\&quot\;/ism", $attributes, $matches);
+ if ($matches[1] != "")
+ $hint = html_entity_decode($matches[1],ENT_QUOTES,'UTF-8');
+
+ $x = random_string();
+
+ $Text = '<br/><div id="' . $x . '"><img src="' . z_root() . '/images/lock_icon.gif" onclick="red_decrypt(\'' . $algorithm . '\',\'' . $hint . '\',\'' . $match[2] . '\',\'#' . $x . '\');" alt="' . t('Encrypted content') . '" title="' . t('Encrypted content') . '" /></div><br />';
+
+ return $Text;
+
+}
+
+
+
function bb_ShareAttributes($match) {
$attributes = $match[1];
@@ -178,6 +210,15 @@ function bb_ShareAttributesSimple($match) {
return($text);
}
+function rpost_callback($match) {
+ if ($match[2]) {
+ return str_replace($match[0],get_rpost_path(get_app()->get_observer()) . '&title=' . urlencode($match[2]) . '&body=' . urlencode($match[3]),$match[0]);
+ } else {
+ return str_replace($match[0],get_rpost_path(get_app()->get_observer()) . '&body=' . urlencode($match[3]),$match[0]);
+ }
+}
+
+
// BBcode 2 HTML was written by WAY2WEB.net
// extended to work with Mistpark/Friendica/Red - Mike Macgirvin
@@ -220,13 +261,15 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true) {
// process [observer] tags before we do anything else because we might
// be stripping away stuff that then doesn't need to be worked on anymore
$observer = $a->get_observer();
- if (strpos($Text,'[/observer]') !== false) {
+ if ((strpos($Text,'[/observer]') !== false) || (strpos($Text,'[/rpost]') !== false)) {
if ($observer) {
$Text = preg_replace("/\[observer\=1\](.*?)\[\/observer\]/ism", '$1', $Text);
$Text = preg_replace("/\[observer\=0\].*?\[\/observer\]/ism", '', $Text);
+ $Text = preg_replace_callback("/\[rpost(=(.*?))?\](.*?)\[\/rpost\]/ism", 'rpost_callback', $Text);
} else {
$Text = preg_replace("/\[observer\=1\].*?\[\/observer\]/ism", '', $Text);
$Text = preg_replace("/\[observer\=0\](.*?)\[\/observer\]/ism", '$1', $Text);
+ $Text = preg_replace("/\[rpost(=.*?)?\](.*?)\[\/rpost\]/ism", '', $Text);
}
}
@@ -266,7 +309,7 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true) {
$Text = str_replace('[observer.url]',$observer['xchan_url'], $Text);
$Text = str_replace('[observer.name]',$observer['xchan_name'], $Text);
$Text = str_replace('[observer.address]',$observer['xchan_addr'], $Text);
- $Text = str_replace('[observer.photo]','[zmg]'.$observer['xchan_photo_l'].'[/zmg]', $Text);
+ $Text = str_replace('[observer.photo]','[zmg]'.$observer['xchan_photo_l'].'[/zmg]', $Text);
} else {
$Text = str_replace('[observer.baseurl]', '', $Text);
$Text = str_replace('[observer.url]','', $Text);
@@ -454,9 +497,10 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true) {
$Text = preg_replace("/\[zmg\](.*?)\[\/zmg\]/ism", '<img class="zrl" src="$1" alt="' . t('Image/photo') . '" />', $Text);
}
- if (strpos($Text,'[crypt]') !== false) {
- $Text = preg_replace("/\[crypt\](.*?)\[\/crypt\]/ism",'<br/><img src="' .$a->get_baseurl() . '/images/lock_icon.gif" alt="' . t('Encrypted content') . '" title="' . t('Encrypted content') . '" /><br />', $Text);
- $Text = preg_replace("/\[crypt=(.*?)\](.*?)\[\/crypt\]/ism",'<br/><img src="' .$a->get_baseurl() . '/images/lock_icon.gif" alt="' . t('Encrypted content') . '" title="' . '$1' . ' ' . t('Encrypted content') . '" /><br />', $Text);
+ if (strpos($Text,'[/crypt]') !== false) {
+ $x = random_string();
+ $Text = preg_replace("/\[crypt\](.*?)\[\/crypt\]/ism",'<br/><div id="' . $x . '"><img src="' .$a->get_baseurl() . '/images/lock_icon.gif" onclick="red_decrypt(\'rot13\',\'\',\'$1\',\'#' . $x . '\');" alt="' . t('Encrypted content') . '" title="' . t('Encrypted content') . '" /><br /></div>', $Text);
+ $Text = preg_replace_callback("/\[crypt (.*?)\](.*?)\[\/crypt\]/ism", 'bb_parse_crypt', $Text);
}
// Try to Oembed
if ($tryoembed) {
diff --git a/include/comanche.php b/include/comanche.php
index 4c6ea2f54..7d7e0e70c 100644
--- a/include/comanche.php
+++ b/include/comanche.php
@@ -2,6 +2,7 @@
require_once('include/security.php');
require_once('include/menu.php');
+require_once('include/widgets.php');
// When editing a webpage - a dropdown is needed to select a page layout
// On submit, the pdl_select value (which is the mid of an item with item_restrict = ITEM_PDL) is stored in
@@ -45,6 +46,12 @@ function pdl_selector($uid,$current="") {
function comanche_parser(&$a,$s) {
+ $cnt = preg_match_all("/\[comment\](.*?)\[\/comment\]/ism", $s, $matches, PREG_SET_ORDER);
+ if($cnt) {
+ foreach($matches as $mtch) {
+ $s = str_replace($mtch[0],'',$s);
+ }
+ }
$cnt = preg_match("/\[layout\](.*?)\[\/layout\]/ism", $s, $matches);
if($cnt)
@@ -171,9 +178,3 @@ function comanche_region(&$a,$s) {
return $s;
}
-
-function widget_profile($args) {
- $a = get_app();
- $block = (((get_config('system','block_public')) && (! local_user()) && (! remote_user())) ? true : false);
- return profile_sidebar($a->profile, $block, true);
-}
diff --git a/include/conversation.php b/include/conversation.php
index a8b3150b4..59ca24d41 100644
--- a/include/conversation.php
+++ b/include/conversation.php
@@ -685,6 +685,7 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $
'str_app' => sprintf( t(' from %s'), $item['app']),
'isotime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'c'),
'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'r'),
+ 'editedtime' => (($item['edited'] != $item['created']) ? sprintf( t('last edited: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['edited'], 'r')) : ''),
'location' => $location,
'indent' => '',
'owner_name' => $owner_name,
@@ -1063,7 +1064,8 @@ function status_editor($a,$x,$popup=false) {
'$audurl' => t("Please enter an audio link/URL:"),
'$term' => t('Tag term:'),
'$fileas' => t('Save to Folder:'),
- '$whereareu' => t('Where are you right now?')
+ '$whereareu' => t('Where are you right now?'),
+ '$expireswhen' => t('Expires YYYY-MM-DD HH:MM')
));
@@ -1072,6 +1074,15 @@ function status_editor($a,$x,$popup=false) {
$jotplugins = '';
$jotnets = '';
+
+ $preview = ((feature_enabled($x['profile_uid'],'preview')) ? t('Preview') : '');
+ if(x($x,'nopreview'))
+ $preview = '';
+
+ $cipher = get_pconfig($x['profile_uid'],'system','default_cipher');
+ if(! $cipher)
+ $cipher = 'aes256';
+
call_hooks('jot_tool', $jotplugins);
call_hooks('jot_networks', $jotnets);
@@ -1080,7 +1091,7 @@ function status_editor($a,$x,$popup=false) {
'$action' => $a->get_baseurl(true) . '/item',
'$share' => (x($x,'button') ? $x['button'] : t('Share')),
'$webpage' => $webpage,
- '$placeholdpagetitle' => t('Page link title'),
+ '$placeholdpagetitle' => ((x($x,'ptlabel')) ? $x['ptlabel'] : t('Page link title')),
'$pagetitle' => (x($x,'pagetitle') ? $x['pagetitle'] : ''),
'$upload' => t('Upload photo'),
'$shortupload' => t('upload photo'),
@@ -1096,7 +1107,7 @@ function status_editor($a,$x,$popup=false) {
'$shortsetloc' => t('set location'),
'$noloc' => t('Clear browser location'),
'$shortnoloc' => t('clear location'),
- '$title' => "",
+ '$title' => ((x($x,'title')) ? htmlspecialchars($x['title']) : ''),
'$placeholdertitle' => t('Set title'),
'$catsenabled' => ((feature_enabled($x['profile_uid'],'categories') && (! $webpage)) ? 'categories' : ''),
'$category' => "",
@@ -1105,7 +1116,7 @@ function status_editor($a,$x,$popup=false) {
'$permset' => t('Permission settings'),
'$shortpermset' => t('permissions'),
'$ptyp' => (($notes_cid) ? 'note' : 'wall'),
- '$content' => '',
+ '$content' => ((x($x,'body')) ? htmlspecialchars($x['body']) : ''),
'$post_id' => '',
'$baseurl' => $a->get_baseurl(true),
'$defloc' => $x['default_location'],
@@ -1121,9 +1132,15 @@ function status_editor($a,$x,$popup=false) {
'$showacl' => ((array_key_exists('showacl',$x)) ? $x['showacl'] : 'yes'),
'$bang' => $x['bang'],
'$profile_uid' => $x['profile_uid'],
- '$preview' => ((feature_enabled($x['profile_uid'],'preview')) ? t('Preview') : ''),
+ '$preview' => $preview,
'$sourceapp' => t($a->sourcename),
'$jotplugins' => $jotplugins,
+ '$defexpire' => '',
+ '$feature_expire' => ((feature_enabled($x['profile_uid'],'content_expire') && (! $webpage)) ? 'block' : 'none'),
+ '$expires' => t('Set expiration date'),
+ '$feature_encrypt' => ((feature_enabled($x['profile_uid'],'content_encrypt') && (! $webpage)) ? 'block' : 'none'),
+ '$encrypt' => t('Encrypt text'),
+ '$cipher' => $cipher,
));
diff --git a/include/dir_fns.php b/include/dir_fns.php
index e234ae0fa..fef58428f 100644
--- a/include/dir_fns.php
+++ b/include/dir_fns.php
@@ -20,6 +20,22 @@ function dir_sort_links() {
return $o;
}
+function dir_safe_mode(&$a) {
+ $observer = get_observer_hash();
+
+ if ($observer)
+ $safe_mode = get_xconfig($observer,'directory','safe_mode');
+ if($safe_mode === '0')
+ $toggle = t('Enable Safe Search');
+ else
+ $toggle = t('Disable Safe Search');
+ $o = replace_macros(get_markup_template('safesearch.tpl'), array(
+ '$safemode' => t('Safe Mode'),
+ '$toggle' => $toggle,
+ ));
+
+ return $o;
+}
function sync_directories($dirmode) {
diff --git a/include/directory.php b/include/directory.php
index 16f819805..491240a9d 100644
--- a/include/directory.php
+++ b/include/directory.php
@@ -31,6 +31,12 @@ function directory_run($argv, $argc){
if(($dirmode == DIRECTORY_MODE_PRIMARY) || ($dirmode == DIRECTORY_MODE_STANDALONE)) {
syncdirs($argv[1]);
+ q("update channel set channel_dirdate = '%s' where channel_id = %d limit 1",
+ dbesc(datetime_convert()),
+ intval($channel['channel_id'])
+ );
+
+
// Now update all the connections
proc_run('php','include/notifier.php','refresh_all',$channel['channel_id']);
return;
@@ -53,6 +59,10 @@ function directory_run($argv, $argc){
// re-queue if unsuccessful
if(! $z['success']) {
+
+ // FIXME - we aren't updating channel_dirdate if we have to queue
+ // the directory packet. That means we'll try again on the next poll run.
+
$hash = random_string();
q("insert into outq ( outq_hash, outq_account, outq_channel, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg )
values ( '%s', %d, %d, '%s', %d, '%s', '%s', '%s', '%s' )",
@@ -67,6 +77,12 @@ function directory_run($argv, $argc){
dbesc('')
);
}
+ else {
+ q("update channel set channel_dirdate = '%s' where channel_id = %d limit 1",
+ dbesc(datetime_convert()),
+ intval($channel['channel_id'])
+ );
+ }
// Now update all the connections
diff --git a/include/enotify.php b/include/enotify.php
index 147023f41..35a554f60 100644
--- a/include/enotify.php
+++ b/include/enotify.php
@@ -60,6 +60,7 @@ function notification($params) {
localize_item($i);
$title = $i['title'];
$body = $i['body'];
+ $private = $i['item_private'];
}
else {
$title = $params['item']['title'];
@@ -196,7 +197,6 @@ function notification($params) {
return;
}
-
$subject = sprintf( t('[Red:Notify] %s tagged you') , $sender['xchan_name']);
$preamble = sprintf( t('%1$s tagged you at %2$s') , $sender['xchan_name'], $sitename);
$epreamble = sprintf( t('%1$s [zrl=%2$s]tagged you[/zrl].') ,
diff --git a/include/features.php b/include/features.php
index 9950039c0..e0c6c63bc 100644
--- a/include/features.php
+++ b/include/features.php
@@ -19,8 +19,8 @@ function get_features() {
// General
'general' => array(
t('General Features'),
-// uncomment when expire is fixed
-// array('expire', t('Content Expiration'), t('Remove old posts/comments after a period of time')),
+// This is per post, and different from fixed expiration 'expire' which isn't working yet
+ array('content_expire', t('Content Expiration'), t('Remove posts/comments and/or private messages at a future time')),
array('multi_profiles', t('Multiple Profiles'), t('Ability to create multiple profiles')),
array('webpages', t('Web Pages'), t('Provide managed web pages on your channel')),
array('prettyphoto', t('Enhanced Photo Albums'), t('Enable photo album with enhanced features')),
@@ -36,6 +36,7 @@ function get_features() {
array('richtext', t('Richtext Editor'), t('Enable richtext editor')),
array('preview', t('Post Preview'), t('Allow previewing posts and comments before publishing them')),
array('channel_sources', t('Channel Sources'), t('Automatically import channel content from other channels or feeds')),
+ array('content_encrypt', t('Even More Encryption'), t('Allow encryption of content end-to-end with a shared secret key')),
),
// Network Tools
diff --git a/include/group.php b/include/group.php
index 7ba14a49d..eece07983 100644
--- a/include/group.php
+++ b/include/group.php
@@ -298,12 +298,13 @@ function expand_groups($a) {
if(! (is_array($a) && count($a)))
return array();
$x = $a;
- stringify_array_elms($x);
+ stringify_array_elms($x,true);
$groups = implode(',', $x);
- $groups = dbesc($groups);
+
if($groups)
- $r = q("SELECT xchan FROM group_member WHERE gid IN ( $groups )");
+ $r = q("SELECT xchan FROM group_member WHERE gid IN ( select id from `group` where hash in ( $groups ))");
$ret = array();
+
if($r)
foreach($r as $rr)
$ret[] = $rr['xchan'];
diff --git a/include/items.php b/include/items.php
index 18aab93fa..520ea7230 100755
--- a/include/items.php
+++ b/include/items.php
@@ -910,6 +910,7 @@ function encode_mail($item) {
$x['message_id'] = $item['mid'];
$x['message_parent'] = $item['parent_mid'];
$x['created'] = $item['created'];
+ $x['expires'] = $item['expires'];
$x['title'] = $item['title'];
$x['body'] = $item['body'];
$x['from'] = encode_item_xchan($item['from']);
@@ -939,6 +940,10 @@ function get_mail_elements($x) {
$arr['title'] = (($x['title'])? htmlentities($x['title'],ENT_COMPAT,'UTF-8',false) : '');
$arr['created'] = datetime_convert('UTC','UTC',$x['created']);
+ if((! array_key_exists('expires',$x)) || ($x['expires'] === '0000-00-00 00:00:00'))
+ $arr['expires'] = '0000-00-00 00:00:00';
+ else
+ $arr['expires'] = datetime_convert('UTC','UTC',$x['expires']);
$arr['mail_flags'] = 0;
@@ -2216,10 +2221,23 @@ function tag_deliver($uid,$item_id) {
intval($item_id)
);
+
+
// At this point we've determined that the person receiving this post was mentioned in it or it is a union.
// Now let's check if this mention was inside a reshare so we don't spam a forum
+ // If it's private we may have to unobscure it momentarily so that we can parse it.
+
+ $body = '';
+
+ if($item['item_flags'] & ITEM_OBSCURED) {
+ $key = get_config('system','prvkey');
+ if($item['body'])
+ $body = aes_unencapsulate(json_decode_plus($item['body']),$key);
+ }
+ else
+ $body = $item['body'];
- $body = preg_replace('/\[share(.*?)\[\/share\]/','',$item['body']);
+ $body = preg_replace('/\[share(.*?)\[\/share\]/','',$body);
$pattern = '/@\[zrl\=' . preg_quote($term['url'],'/') . '\]' . preg_quote($u[0]['channel_name'],'/') . '\[\/zrl\]/';
@@ -2452,6 +2470,7 @@ function mail_store($arr) {
$arr['from_xchan'] = ((x($arr,'from_xchan')) ? notags(trim($arr['from_xchan'])) : '');
$arr['to_xchan'] = ((x($arr,'to_xchan')) ? notags(trim($arr['to_xchan'])) : '');
$arr['created'] = ((x($arr,'created') !== false) ? datetime_convert('UTC','UTC',$arr['created']) : datetime_convert());
+ $arr['expires'] = ((x($arr,'expires') !== false) ? datetime_convert('UTC','UTC',$arr['expires']) : '0000-00-00 00:00:00');
$arr['title'] = ((x($arr,'title')) ? notags(trim($arr['title'])) : '');
$arr['parent_mid'] = ((x($arr,'parent_mid')) ? notags(trim($arr['parent_mid'])) : '');
$arr['body'] = ((x($arr,'body')) ? trim($arr['body']) : '');
diff --git a/include/js_strings.php b/include/js_strings.php
index 2e4f70774..afa8f075a 100644
--- a/include/js_strings.php
+++ b/include/js_strings.php
@@ -2,13 +2,15 @@
function js_strings() {
return replace_macros(get_markup_template('js_strings.tpl'), array(
- '$delitem' => t('Delete this item?'),
- '$comment' => t('Comment'),
- '$showmore' => t('show more'),
- '$showfewer' => t('show fewer'),
- '$pwshort' => t("Password too short"),
- '$pwnomatch' => t("Passwords do not match"),
- '$everybody' => t('everybody'),
+ '$delitem' => t('Delete this item?'),
+ '$comment' => t('Comment'),
+ '$showmore' => t('show more'),
+ '$showfewer' => t('show fewer'),
+ '$pwshort' => t("Password too short"),
+ '$pwnomatch' => t("Passwords do not match"),
+ '$everybody' => t('everybody'),
+ '$passphrase' => t('Secret Passphrase'),
+ '$passhint' => t('Passphrase hint'),
'$t01' => ((t('timeago.prefixAgo') != 'timeago.prefixAgo') ? t('timeago.prefixAgo') : 'null'),
'$t02' => ((t('timeago.suffixAgo') != 'timeago.suffixAgo') ? t('timeago.suffixAgo') : 'null'),
diff --git a/include/message.php b/include/message.php
index e54a6cd83..3bcd5e209 100644
--- a/include/message.php
+++ b/include/message.php
@@ -8,7 +8,7 @@ require_once('include/attach.php');
// send a private message
-function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto=''){
+function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto='',$expires = ''){
$ret = array('success' => false);
@@ -22,6 +22,10 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto='
if(! strlen($subject))
$subject = t('[no subject]');
+// if(! $expires)
+// $expires = '0000-00-00 00:00:00';
+// else
+// $expires = datetime_convert(date_default_timezone_get(),'UTC',$expires);
if($uid) {
$r = q("select * from channel where channel_id = %d limit 1",
@@ -111,8 +115,8 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto='
- $r = q("INSERT INTO mail ( account_id, mail_flags, channel_id, from_xchan, to_xchan, title, body, attach, mid, parent_mid, created )
- VALUES ( %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )",
+ $r = q("INSERT INTO mail ( account_id, mail_flags, channel_id, from_xchan, to_xchan, title, body, attach, mid, parent_mid, created, expires )
+ VALUES ( %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )",
intval($channel['channel_account_id']),
intval(MAIL_OBSCURED),
intval($channel['channel_id']),
@@ -123,7 +127,8 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto='
dbesc($jattach),
dbesc($mid),
dbesc($replyto),
- dbesc(datetime_convert())
+ dbesc(datetime_convert()),
+ dbesc($expires)
);
// verify the save
diff --git a/include/oembed.php b/include/oembed.php
index 04a40f6ee..5da842170 100755
--- a/include/oembed.php
+++ b/include/oembed.php
@@ -123,6 +123,7 @@ function oembed_format_object($j){
if ( $j->type!='rich' || !strpos($j->html,$embedurl) ){
$embedlink = (isset($j->title))?$j->title:$embedurl;
$ret .= "<a href='$embedurl' rel='oembed'>$embedlink</a>";
+ $ret .= "<br>";
if (isset($j->author_name)) $ret.=" by ".$j->author_name;
if (isset($j->provider_name)) $ret.=" on ".$j->provider_name;
} else {
diff --git a/include/poller.php b/include/poller.php
index 94ca99e54..3c4e6402c 100644
--- a/include/poller.php
+++ b/include/poller.php
@@ -21,6 +21,11 @@ function poller_run($argv, $argc){
}
}
+ $interval = intval(get_config('system','poll_interval'));
+ if(! $interval)
+ $interval = ((get_config('system','delivery_interval') === false) ? 3 : intval(get_config('system','delivery_interval')));
+
+
logger('poller: start');
// run queue delivery process in the background
@@ -37,7 +42,34 @@ function poller_run($argv, $argc){
intval(ACCOUNT_EXPIRED),
intval(ACCOUNT_EXPIRED)
);
+
+ // expire any expired mail
+
+ q("delete from mail where expires != '0000-00-00 00:00:00' and expires < UTC_TIMESTAMP() ");
+
+ $r = q("select id from item where expires != '0000-00-00 00:00:00' and expires < UTC_TIMESTAMP()
+ and not ( item_restrict & %d ) ",
+ intval(ITEM_DELETED)
+ );
+ if($r) {
+ require_once('include/items.php');
+ foreach($r as $rr)
+ drop_item($rr['id'],false);
+ }
+ // Ensure that every channel pings a directory server once a month. This way we can discover
+ // channels and sites that quietly vanished and prevent the directory from accumulating stale
+ // or dead entries.
+
+ $r = q("select channel_id from channel where channel_dirdate < UTC_TIMESTAMP() - INTERVAL 30 DAY");
+ if($r) {
+ foreach($r as $rr) {
+ proc_run('php','include/directory.php',$rr['channel_id']);
+ if($interval)
+ @time_sleep_until(microtime(true) + (float) $interval);
+ }
+ }
+
// publish any applicable items that were set to be published in the future
// (time travel posts)
@@ -134,9 +166,6 @@ function poller_run($argv, $argc){
$force = true;
}
- $interval = intval(get_config('system','poll_interval'));
- if(! $interval)
- $interval = ((get_config('system','delivery_interval') === false) ? 3 : intval(get_config('system','delivery_interval')));
$sql_extra = (($manual_id) ? " AND abook_id = $manual_id " : "");
diff --git a/include/reddav.php b/include/reddav.php
new file mode 100644
index 000000000..c24414610
--- /dev/null
+++ b/include/reddav.php
@@ -0,0 +1,196 @@
+<?php /** @file */
+
+use Sabre\DAV;
+ require_once('vendor/autoload.php');
+
+class RedInode implements DAV\INode {
+
+ private $attach;
+
+ function __construct($attach) {
+ $this->attach = $attach;
+ }
+
+
+ function delete() {
+ if(! perm_is_allowed($this->channel_id,'','view_storage'))
+ return;
+
+ /**
+ * Since I don't believe this is documented elsewhere -
+ * ATTACH_FLAG_OS means that the file contents are stored in the OS
+ * rather than in the DB - as is the case for attachments.
+ * Exactly how they are stored (what path and filename) are still
+ * TBD. We will probably not be using the original filename but
+ * instead the attachment 'hash' as this will prevent folks from
+ * uploading PHP code onto misconfigured servers and executing it.
+ * It's easy to misconfigure servers because we can provide a
+ * rule for Apache, but folks using nginx will then be susceptible.
+ * Then there are those who don't understand these kinds of exploits
+ * and don't have any idea allowing uploaded PHP files to be executed
+ * by the server could be a problem. We also don't have any idea what
+ * executable types are served on their system - like .py, .pyc, .pl, .sh
+ * .cgi, .exe, .bat, .net, whatever.
+ */
+
+ if($this->attach['flags'] & ATTACH_FLAG_OS) {
+ // FIXME delete physical file
+ }
+ if($this->attach['flags'] & ATTACH_FLAG_DIR) {
+ // FIXME delete contents (recursive?)
+ }
+
+ q("delete from attach where id = %d limit 1",
+ intval($this->attach['id'])
+ );
+
+ }
+
+ function getName() {
+ return $this->attach['filename'];
+ }
+
+ function setName($newName) {
+
+ if((! $newName) || (! perm_is_allowed($this->channel_id,'','view_storage')))
+ return;
+
+ $this->attach['filename'] = $newName;
+ $r = q("update attach set filename = '%s' where id = %d limit 1",
+ dbesc($this->attach['filename']),
+ intval($this->attach['id'])
+ );
+
+ }
+
+ function getLastModified() {
+ return $this->attach['edited'];
+ }
+
+}
+
+
+abstract class RedDirectory extends DAV\Node implements DAV\ICollection {
+
+ private $red_path;
+ private $dir_key;
+ private $auth;
+ private $channel_id;
+
+ function __construct($red_path,$auth_plugin) {
+ $this->red_path = $red_path;
+ $this->auth = $auth_plugin;
+ }
+
+ function getChildren() {
+
+ if(! perm_is_allowed($this->channel_id,'','view_storage'))
+ return array();
+
+ $ret = array();
+ $r = q("select distinct filename from attach where folder = '%s' and uid = %d group by filename",
+ dbesc($this->dir_key),
+ intval($this->channel_id)
+ );
+ if($r) {
+ foreach($r as $rr) {
+ $ret[] = $rr['filename'];
+ }
+ }
+ return $ret;
+
+ }
+
+
+ function getChild($name) {
+ if(! perm_is_allowed($this->channel_id,'','view_storage')) {
+ throw new DAV\Exception\Forbidden('Permission denied.');
+ return;
+ }
+
+// FIXME check revisions
+
+ $r = q("select * from attach where folder = '%s' and filename = '%s' and uid = %d limit 1",
+ dbesc($this->dir_key),
+ dbesc($name),
+ dbesc($this->channel_id)
+ );
+ if(! $r) {
+ throw new DAV\Exception\NotFound('The file with name: ' . $name . ' could not be found');
+ }
+
+
+ }
+
+
+ function createFile($name,$data = null) {
+
+
+ }
+
+ function createDirectory($name) {
+
+
+
+ }
+
+
+ function childExists($name) {
+ $r = q("select distinct filename from attach where folder = '%s' and filename = '%s' and uid = %d group by filename",
+ dbesc($this->dir_key),
+ dbesc($name),
+ intval($this->channel_id)
+ );
+ if($r)
+ return true;
+ return false;
+
+ }
+
+}
+
+
+abstract class RedFile extends DAV\Node implements DAV\IFile {
+
+ private $data;
+
+
+ function __construct($data) {
+ $this->data = $data;
+
+ }
+
+
+
+ function put($data) {
+
+ }
+
+
+ function get() {
+
+
+ }
+
+ function getETag() {
+
+
+
+ }
+
+
+ function getContentType() {
+ return $this->data['filetype'];
+ }
+
+
+ function getSize() {
+ return $this->data['filesize'];
+ }
+
+}
+
+
+
+
+
diff --git a/include/taxonomy.php b/include/taxonomy.php
index 85396a51d..5159dad02 100644
--- a/include/taxonomy.php
+++ b/include/taxonomy.php
@@ -96,13 +96,14 @@ function format_term_for_display($term) {
// Tag cloud functions - need to be adpated to this database format
-function tagadelic($uid, $count = 0, $authors = '', $flags = 0, $type = TERM_HASHTAG) {
+function tagadelic($uid, $count = 0, $authors = '', $flags = 0, $restrict = 0, $type = TERM_HASHTAG) {
$sql_options = '';
$count = intval($count);
if($flags)
$sql_options .= " and ((item_flags & " . intval($flags) . ") = " . intval($flags) . ") ";
+
if($authors) {
if(! is_array($authors))
$authors = array($authors);
@@ -113,12 +114,13 @@ function tagadelic($uid, $count = 0, $authors = '', $flags = 0, $type = TERM_HAS
// Fetch tags
$r = q("select term, count(term) as total from term left join item on term.oid = item.id
where term.uid = %d and term.type = %d
- and otype = %d and item_restrict = 0 and item_private = 0
+ and otype = %d and item_restrict = %d and item_private = 0
$sql_options
group by term order by total desc %s",
intval($uid),
intval($type),
intval(TERM_OBJ_POST),
+ intval($restrict),
((intval($count)) ? "limit $count" : '')
);
@@ -199,10 +201,10 @@ function dir_tagadelic($count = 0) {
}
-function tagblock($link,$uid,$count = 0,$authors = '',$flags = 0,$type = TERM_HASHTAG) {
+function tagblock($link,$uid,$count = 0,$authors = '',$flags = 0,$restrict = 0,$type = TERM_HASHTAG) {
$o = '';
$tab = 0;
- $r = tagadelic($uid,$count,$authors,$flags,$type);
+ $r = tagadelic($uid,$count,$authors,$flags,$restrict,$type);
if($r) {
$o = '<div class="tagblock widget"><h3>' . t('Tags') . '</h3><div class="tags" align="center">';
diff --git a/include/text.php b/include/text.php
index 1ff9d27cb..fc70e3509 100755
--- a/include/text.php
+++ b/include/text.php
@@ -878,6 +878,7 @@ function smilies($s, $sample = false) {
':like',
':dislike',
'red#',
+ 'r#',
'~friendica'
);
@@ -916,6 +917,7 @@ function smilies($s, $sample = false) {
'<img class="smiley" src="' . $a->get_baseurl() . '/images/like.gif" alt=":like" />',
'<img class="smiley" src="' . $a->get_baseurl() . '/images/dislike.gif" alt=":dislike" />',
'<a href="http://getzot.com"><img class="smiley" src="' . $a->get_baseurl() . '/images/rhash-16.png" alt="red#" /> the Red Matrix</a>',
+ '<a href="http://getzot.com"><img class="smiley" src="' . $a->get_baseurl() . '/images/rhash-16.png" alt="r#" /> the Red Matrix</a>',
'<a href="http://friendica.com">~friendica <img class="smiley" src="' . $a->get_baseurl() . '/images/friendica-16.png" alt="~friendica" /></a>'
);
@@ -1344,7 +1346,7 @@ function get_plink($item,$mode) {
else
$key = 'llink';
- if (x($item,$key) && ($item['item_private'] != 1)) {
+ if(x($item,$key)) {
return array(
'href' => zid($item[$key]),
'title' => t('link to source'),
diff --git a/include/widgets.php b/include/widgets.php
new file mode 100644
index 000000000..87941f40f
--- /dev/null
+++ b/include/widgets.php
@@ -0,0 +1,34 @@
+<?php /** @file */
+
+
+function widget_profile($args) {
+ $a = get_app();
+ $block = (((get_config('system','block_public')) && (! local_user()) && (! remote_user())) ? true : false);
+ return profile_sidebar($a->profile, $block, true);
+}
+
+// FIXME The problem with the next widget is that we don't have a search function for webpages that we can send the links to.
+// Then we should also provide an option to search webpages and conversations.
+
+function widget_tagcloud($args) {
+
+ $o = '';
+ $tab = 0;
+ $a = get_app();
+ $uid = $a->profile_uid;
+ $count = ((x($args,'count')) ? intval($args['count']) : 24);
+ $flags = 0;
+ $type = TERM_CATEGORY;
+
+ $r = tagadelic($uid,$count,$authors,$flags,ITEM_WEBPAGE,$type);
+
+ if($r) {
+ $o = '<div class="tagblock widget"><h3>' . t('Categories') . '</h3><div class="tags" align="center">';
+ foreach($r as $rr) {
+ $o .= '<span class="tag'.$rr[2].'">'.$rr[0].'</span> ' . "\r\n";
+ }
+ $o .= '</div></div>';
+ }
+ return $o;
+}
+
diff --git a/include/zot.php b/include/zot.php
index 91729f9de..c7c5c52b7 100644
--- a/include/zot.php
+++ b/include/zot.php
@@ -1567,6 +1567,11 @@ function import_directory_keywords($hash,$keywords) {
function update_modtime($hash,$guid,$addr,$flags = 0) {
+ $dirmode = intval(get_config('system','directory_mode'));
+
+ if($dirmode == DIRECTORY_MODE_NORMAL)
+ return;
+
if($flags) {
q("insert into updates (ud_hash, ud_guid, ud_date, ud_flags, ud_addr ) values ( '%s', '%s', '%s', %d, '%s' )",
dbesc($hash),
@@ -1640,20 +1645,23 @@ function import_site($arr,$pubkey) {
$directory_url = htmlentities($arr['directory_url'],ENT_COMPAT,'UTF-8',false);
$url = htmlentities($arr['url'],ENT_COMPAT,'UTF-8',false);
$sellpage = htmlentities($arr['sellpage'],ENT_COMPAT,'UTF-8',false);
+ $site_location = htmlentities($arr['location'],ENT_COMPAT,'UTF-8',false);
if($exists) {
if(($siterecord['site_flags'] != $site_directory)
|| ($siterecord['site_access'] != $access_policy)
|| ($siterecord['site_directory'] != $directory_url)
|| ($siterecord['site_sellpage'] != $sellpage)
+ || ($siterecord['site_location'] != $site_location)
|| ($siterecord['site_register'] != $register_policy)) {
$update = true;
// logger('import_site: input: ' . print_r($arr,true));
// logger('import_site: stored: ' . print_r($siterecord,true));
- $r = q("update site set site_flags = %d, site_access = %d, site_directory = '%s', site_register = %d, site_update = '%s', site_sellpage = '%s'
+ $r = q("update site set site_location = '%s', site_flags = %d, site_access = %d, site_directory = '%s', site_register = %d, site_update = '%s', site_sellpage = '%s'
where site_url = '%s' limit 1",
+ dbesc($site_location),
intval($site_directory),
intval($access_policy),
dbesc($directory_url),
@@ -1669,11 +1677,12 @@ function import_site($arr,$pubkey) {
}
else {
$update = true;
- $r = q("insert into site ( site_url, site_access, site_flags, site_update, site_directory, site_register, site_sellpage )
- values ( '%s', %d, %d, '%s', '%s', %d, '%s' )",
+ $r = q("insert into site ( site_location, site_url, site_access, site_flags, site_update, site_directory, site_register, site_sellpage )
+ values ( '%s', '%s', %d, %d, '%s', '%s', %d, '%s' )",
+ dbesc($site_location),
dbesc($url),
- intval($site_directory),
intval($access_policy),
+ intval($site_directory),
dbesc(datetime_convert()),
dbesc($directory_url),
intval($register_policy),
@@ -1896,3 +1905,14 @@ function process_channel_sync_delivery($sender,$arr,$deliveries) {
}
return $result;
}
+
+// We probably should make rpost discoverable.
+
+function get_rpost_path($observer) {
+ if(! $observer)
+ return '';
+ $parsed = parse_url($observer['xchan_url']);
+ return $parsed['scheme'] . '://' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : '') . '/rpost?f=';
+
+}
+