diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/Contact.php | 26 | ||||
-rw-r--r-- | include/ItemObject.php | 1 | ||||
-rw-r--r-- | include/attach.php | 133 | ||||
-rw-r--r-- | include/bbcode.php | 56 | ||||
-rw-r--r-- | include/comanche.php | 13 | ||||
-rw-r--r-- | include/conversation.php | 27 | ||||
-rw-r--r-- | include/dir_fns.php | 16 | ||||
-rw-r--r-- | include/directory.php | 16 | ||||
-rw-r--r-- | include/enotify.php | 2 | ||||
-rw-r--r-- | include/features.php | 5 | ||||
-rw-r--r-- | include/group.php | 7 | ||||
-rwxr-xr-x | include/items.php | 21 | ||||
-rw-r--r-- | include/js_strings.php | 16 | ||||
-rw-r--r-- | include/message.php | 13 | ||||
-rwxr-xr-x | include/oembed.php | 1 | ||||
-rw-r--r-- | include/poller.php | 35 | ||||
-rw-r--r-- | include/reddav.php | 196 | ||||
-rw-r--r-- | include/taxonomy.php | 10 | ||||
-rwxr-xr-x | include/text.php | 4 | ||||
-rw-r--r-- | include/widgets.php | 34 | ||||
-rw-r--r-- | include/zot.php | 28 |
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=\"\;(.*?)\"\;/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=\"\;(.*?)\"\;/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='; + +} + |