diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/Contact.php | 3 | ||||
-rw-r--r-- | include/ConversationObject.php | 33 | ||||
-rw-r--r-- | include/ItemObject.php | 139 | ||||
-rw-r--r-- | include/bbcode.php | 9 | ||||
-rw-r--r-- | include/cli_startup.php | 1 | ||||
-rw-r--r-- | include/config.php | 314 | ||||
-rw-r--r-- | include/contact_selectors.php | 16 | ||||
-rw-r--r-- | include/conversation.php | 101 | ||||
-rw-r--r-- | include/deliver.php | 13 | ||||
-rw-r--r-- | include/dir_fns.php | 5 | ||||
-rw-r--r-- | include/directory.php | 21 | ||||
-rw-r--r-- | include/enotify.php | 21 | ||||
-rw-r--r-- | include/features.php | 1 | ||||
-rwxr-xr-x | include/items.php | 172 | ||||
-rw-r--r-- | include/network.php | 20 | ||||
-rw-r--r-- | include/notifier.php | 69 | ||||
-rw-r--r-- | include/permissions.php | 16 | ||||
-rw-r--r-- | include/poller.php | 3 | ||||
-rw-r--r-- | include/profile_advanced.php | 35 | ||||
-rw-r--r-- | include/settings.php | 99 | ||||
-rw-r--r-- | include/taxonomy.php | 208 | ||||
-rwxr-xr-x | include/text.php | 375 | ||||
-rw-r--r-- | include/zot.php | 87 |
23 files changed, 1061 insertions, 700 deletions
diff --git a/include/Contact.php b/include/Contact.php index b2d459ca4..245682454 100644 --- a/include/Contact.php +++ b/include/Contact.php @@ -76,6 +76,9 @@ function abook_toggle_flag($abook,$flag) { intval($abook['abook_id']), intval($abook['abook_channel']) ); + $a = get_app(); + if($a->data['abook']) + $a->data['abook']['abook_flags'] = $a->data['abook']['abook_flags'] ^ $flag; return $r; } diff --git a/include/ConversationObject.php b/include/ConversationObject.php index 7cf39f757..3f5e901d3 100644 --- a/include/ConversationObject.php +++ b/include/ConversationObject.php @@ -11,12 +11,14 @@ require_once('include/text.php'); /** * A list of threads * - * We should think about making this a SPL Iterator */ + class Conversation extends BaseObject { private $threads = array(); private $mode = null; + private $observer = null; private $writable = false; + private $commentable = false; private $profile_owner = 0; private $preview = false; @@ -34,8 +36,8 @@ class Conversation extends BaseObject { $a = $this->get_app(); - $observer = $a->get_observer(); - $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + $this->observer = $a->get_observer(); + $ob_hash = (($this->observer) ? $this->observer['xchan_hash'] : ''); switch($mode) { case 'network': @@ -63,7 +65,6 @@ class Conversation extends BaseObject { break; } $this->mode = $mode; - } /** @@ -80,6 +81,10 @@ class Conversation extends BaseObject { return $this->writable; } + public function is_commentable() { + return $this->commentable; + } + /** * Check if page is a preview */ @@ -101,6 +106,10 @@ class Conversation extends BaseObject { $this->set_mode($mode); } + public function get_observer() { + return $this->observer; + } + /** * Add a thread to the conversation @@ -121,12 +130,24 @@ class Conversation extends BaseObject { } /* - * Only add will be displayed + * Only add things that will be displayed */ - if(activity_match($item->get_data_value('verb'),ACTIVITY_LIKE) || activity_match($item->get_data_value('verb'),ACTIVITY_DISLIKE)) { + + if(($item->get_data_value('id') != $item->get_data_value('parent')) && (activity_match($item->get_data_value('verb'),ACTIVITY_LIKE) || activity_match($item->get_data_value('verb'),ACTIVITY_DISLIKE))) { return false; } + + if(local_user() && $item->get_data_value('uid') == local_user()) + $this->commentable = true; + + if($this->writable) + $this->commentable = true; + + if(($this->observer) && (! $this->writable)) { + $this->commentable = can_comment_on_post($this->observer['xchan_hash'],$item->data); + } + $item->set_conversation($this); $this->threads[] = $item; return end($this->threads); diff --git a/include/ItemObject.php b/include/ItemObject.php index ccd192ff5..7a9e43819 100644 --- a/include/ItemObject.php +++ b/include/ItemObject.php @@ -11,12 +11,10 @@ require_once('boot.php'); * An item */ class Item extends BaseObject { - private $data = array(); + public $data = array(); private $template = 'conv_item.tpl'; private $comment_box_template = 'comment_item.tpl'; private $toplevel = false; - private $writable = false; - private $commentable = false; private $children = array(); private $parent = null; private $conversation = null; @@ -27,31 +25,15 @@ class Item extends BaseObject { private $wall_to_wall = false; private $threaded = false; private $visiting = false; - private $observer = null; private $channel = null; public function __construct($data) { $a = $this->get_app(); $this->data = $data; - $this->channel = $a->get_channel(); - $this->observer = $a->get_observer(); - $this->toplevel = ($this->get_id() == $this->get_data_value('parent')); - $this->writable = (((local_user()) && ($this->channel['channel_hash'] === $this->data['owner_xchan'])) ? true : false); - $this->commentable = $this->writable; - - if(($this->observer) && (! $this->writable)) { - $this->commentable = perm_is_allowed($this->data['uid'],$this->observer['xchan_hash'],'post_comments'); - } - -// logger('writable: ' . $this->writable); -// logger('commentable: ' . $this->commentable . ' uid=' . $this->data['uid'] . ' observer=' . $this->observer['xchan_hash']); -// if(get_config('system','thread_allow') && $a->theme_thread_allow && !$this->is_toplevel()) -// $this->threaded = true; - // Prepare the children if(count($data['children'])) { foreach($data['children'] as $item) { @@ -85,7 +67,6 @@ class Item extends BaseObject { $result = array(); $a = $this->get_app(); - $observer = $this->observer; $item = $this->get_data(); $commentww = ''; @@ -99,6 +80,7 @@ class Item extends BaseObject { $total_children = $this->count_descendants(); $conv = $this->get_conversation(); + $observer = $conv->get_observer(); $lock = ((($item['item_private'] == 1) || (($item['uid'] == local_user()) && (strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])))) @@ -111,10 +93,9 @@ class Item extends BaseObject { else $edpost = false; -// FIXME - this is wrong. -// if(($this->get_data_value('uid') == local_user()) || $this->is_visiting()) - - if($this->get_data_value('uid') == local_user()) + if($observer['xchan_hash'] == $this->get_data_value('author_xchan') + || $observer['xchan_hash'] == $this->get_data_value('owner_xchan') + || $this->get_data_value('uid') == local_user()) $dropping = true; if($dropping) { @@ -123,7 +104,7 @@ class Item extends BaseObject { 'delete' => t('Delete'), ); } - +// FIXME if($observer_is_pageowner) { $multidrop = array( 'select' => t('Select'), @@ -152,6 +133,7 @@ class Item extends BaseObject { $this->check_wall_to_wall(); if($this->is_toplevel()) { + // FIXME check this permission if($conv->get_profile_owner() == local_user()) { // FIXME we don't need all this stuff, some can be done in the template @@ -166,16 +148,20 @@ class Item extends BaseObject { 'starred' => t('starred'), ); - $tagger = array( - 'tagit' => t("add tag"), - 'classtagger' => "", - ); } } else { $indent = 'comment'; } - if($this->is_commentable()) { + // FIXME - check this permission + if($conv->get_profile_owner() == local_user()) { + $tagger = array( + 'tagit' => t("add tag"), + 'classtagger' => "", + ); + } + + if($conv->is_commentable()) { $like = array( t("I like this \x28toggle\x29"), t("like")); $dislike = array( t("I don't like this \x28toggle\x29"), t("dislike")); if ($shareable) @@ -456,28 +442,6 @@ class Item extends BaseObject { } /** - * Check if this is writable - */ - private function is_writable() { - - return $this->writable; - -// $conv = $this->get_conversation(); - -// return true; - -// if($conv) { - // This will allow us to comment on wall-to-wall items owned by our friends - // and community forums even if somebody else wrote the post. -// return ($this->writable || ($this->is_visiting() && $conv->get_mode() == 'channel')); -// } - } - - private function is_commentable() { - return $this->commentable; - } - - /** * Count the total of our descendants */ private function count_descendants() { @@ -514,44 +478,43 @@ class Item extends BaseObject { $comment_box = ''; $conv = $this->get_conversation(); - if(! $this->is_commentable()) + if(! $conv->is_commentable()) return; - if($conv->is_writable() || $this->is_writable()) { - $template = get_markup_template($this->get_comment_box_template()); - - $a = $this->get_app(); - - $qc = ((local_user()) ? get_pconfig(local_user(),'system','qcomment') : null); - $qcomment = (($qc) ? explode("\n",$qc) : null); - - $comment_box = replace_macros($template,array( - '$return_path' => '', - '$threaded' => $this->is_threaded(), - '$jsreload' => (($conv->get_mode() === 'display') ? $_SESSION['return_url'] : ''), - '$type' => (($conv->get_mode() === 'channel') ? 'wall-comment' : 'net-comment'), - '$id' => $this->get_id(), - '$parent' => $this->get_id(), - '$qcomment' => $qcomment, - '$profile_uid' => $conv->get_profile_owner(), - '$mylink' => $this->observer['xchan_url'], - '$mytitle' => t('This is you'), - '$myphoto' => $this->observer['xchan_photo_s'], - '$comment' => t('Comment'), - '$submit' => t('Submit'), - '$edbold' => t('Bold'), - '$editalic' => t('Italic'), - '$eduline' => t('Underline'), - '$edquote' => t('Quote'), - '$edcode' => t('Code'), - '$edimg' => t('Image'), - '$edurl' => t('Link'), - '$edvideo' => t('Video'), - '$preview' => ((feature_enabled($conv->get_profile_owner(),'preview')) ? t('Preview') : ''), - '$indent' => $indent, - '$sourceapp' => get_app()->sourcename - )); - } + $template = get_markup_template($this->get_comment_box_template()); + + $a = $this->get_app(); + $observer = $conv->get_observer(); + + $qc = ((local_user()) ? get_pconfig(local_user(),'system','qcomment') : null); + $qcomment = (($qc) ? explode("\n",$qc) : null); + + $comment_box = replace_macros($template,array( + '$return_path' => '', + '$threaded' => $this->is_threaded(), + '$jsreload' => (($conv->get_mode() === 'display') ? $_SESSION['return_url'] : ''), + '$type' => (($conv->get_mode() === 'channel') ? 'wall-comment' : 'net-comment'), + '$id' => $this->get_id(), + '$parent' => $this->get_id(), + '$qcomment' => $qcomment, + '$profile_uid' => $conv->get_profile_owner(), + '$mylink' => $observer['xchan_url'], + '$mytitle' => t('This is you'), + '$myphoto' => $observer['xchan_photo_s'], + '$comment' => t('Comment'), + '$submit' => t('Submit'), + '$edbold' => t('Bold'), + '$editalic' => t('Italic'), + '$eduline' => t('Underline'), + '$edquote' => t('Quote'), + '$edcode' => t('Code'), + '$edimg' => t('Image'), + '$edurl' => t('Link'), + '$edvideo' => t('Video'), + '$preview' => ((feature_enabled($conv->get_profile_owner(),'preview')) ? t('Preview') : ''), + '$indent' => $indent, + '$sourceapp' => get_app()->sourcename + )); return $comment_box; } diff --git a/include/bbcode.php b/include/bbcode.php index 4f99a8038..862570348 100644 --- a/include/bbcode.php +++ b/include/bbcode.php @@ -424,11 +424,14 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true) { $Text = preg_replace_callback("/\[video\](.*?)\[\/video\]/ism", 'tryoembed', $Text); $Text = preg_replace_callback("/\[audio\](.*?)\[\/audio\]/ism", 'tryoembed', $Text); - } else { - $Text = preg_replace("/\[video\](.*?)\[\/video\]/", '$1', $Text); - $Text = preg_replace("/\[audio\](.*?)\[\/audio\]/", '$1', $Text); } + // if video couldn't be embedded, link to it instead. + + $Text = preg_replace("/\[video\](.*?)\[\/video\]/", '<a href="$1">$1</a>', $Text); + $Text = preg_replace("/\[audio\](.*?)\[\/audio\]/", '<a href="$1">$1</a>', $Text); + + // html5 video and audio diff --git a/include/cli_startup.php b/include/cli_startup.php index 1d5861541..6bd4e7520 100644 --- a/include/cli_startup.php +++ b/include/cli_startup.php @@ -21,7 +21,6 @@ function cli_startup() { require_once('include/session.php'); - load_config('config'); load_config('system'); $a->set_baseurl(get_config('system','baseurl')); diff --git a/include/config.php b/include/config.php index 5db0a3d05..1f7a4dbd7 100644 --- a/include/config.php +++ b/include/config.php @@ -17,20 +17,23 @@ function load_config($family) { global $a; - $r = q("SELECT * FROM config WHERE cat = '%s'", dbesc($family)); - if($r) { - foreach($r as $rr) { - $k = $rr['k']; - if ($family === 'config') { - $a->config[$k] = $rr['v']; - } else { - $a->config[$family][$k] = $rr['v']; + + if(! array_key_exists($family,$a->config)) + $a->config[$family] = array(); + + if(! array_key_exists('config_loaded',$a->config[$family])) { + + $r = q("SELECT * FROM config WHERE cat = '%s'", dbesc($family)); + if($r !== false) { + if($r) { + foreach($r as $rr) { + $k = $rr['k']; + $a->config[$family][$k] = $rr['v']; + } } + $a->config[$family]['config_loaded'] = true; } - } else if ($family != 'config') { - // Negative caching - $a->config[$family] = "!<unset>!"; - } + } } // get a particular config variable given the family name @@ -42,54 +45,49 @@ function load_config($family) { // to hit the DB again for this item. -function get_config($family, $key, $instore = false) { +function get_config($family, $key) { global $a; - if(! $instore) { - // Looking if the whole family isn't set - if(isset($a->config[$family])) { - if($a->config[$family] === '!<unset>!') { - return false; - } - } + if((! array_key_exists($family,$a->config)) || (! array_key_exists('config_loaded',$a->config[$family]))) + load_config($family); - if(isset($a->config[$family][$key])) { - if($a->config[$family][$key] === '!<unset>!') { - return false; - } - return $a->config[$family][$key]; + if(array_key_exists('config_loaded',$a->config[$family])) { + if(! array_key_exists($key,$a->config[$family])) { + return false; } + return ((preg_match('|^a:[0-9]+:{.*}$|s', $a->config[$family][$key])) + ? unserialize($a->config[$family][$key]) + : $a->config[$family][$key] + ); } - $ret = q("SELECT `v` FROM `config` WHERE `cat` = '%s' AND `k` = '%s' LIMIT 1", + return false; +} + +function get_config_from_storage($family,$key) { + $ret = q("select * from config where cat = '%s' and k = '%s' limit 1", dbesc($family), dbesc($key) ); - if(count($ret)) { - // manage array value - $val = (preg_match("|^a:[0-9]+:{.*}$|s", $ret[0]['v'])?unserialize( $ret[0]['v']):$ret[0]['v']); - $a->config[$family][$key] = $val; - return $val; - } - else { - $a->config[$family][$key] = '!<unset>!'; - } - return false; + return $ret; } + + // Store a config value ($value) in the category ($family) // under the key ($key) // Return the value, or false if the database update failed - function set_config($family,$key,$value) { global $a; // manage array value - $dbvalue = (is_array($value)?serialize($value):$value); - $dbvalue = (is_bool($dbvalue) ? intval($dbvalue) : $dbvalue); - if(get_config($family,$key,true) === false) { + $dbvalue = ((is_array($value)) ? serialize($value) : $value); + $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue); + + if(get_config($family,$key) === false || (! get_config_from_storage($family,$key))) { $a->config[$family][$key] = $value; - $ret = q("INSERT INTO `config` ( `cat`, `k`, `v` ) VALUES ( '%s', '%s', '%s' ) ", + + $ret = q("INSERT INTO config ( cat, k, v ) VALUES ( '%s', '%s', '%s' ) ", dbesc($family), dbesc($key), dbesc($dbvalue) @@ -99,7 +97,7 @@ function set_config($family,$key,$value) { return $ret; } - $ret = q("UPDATE `config` SET `v` = '%s' WHERE `cat` = '%s' AND `k` = '%s' LIMIT 1", + $ret = q("UPDATE config SET v = '%s' WHERE cat = '%s' AND k = '%s' LIMIT 1", dbesc($dbvalue), dbesc($family), dbesc($key) @@ -112,14 +110,11 @@ function set_config($family,$key,$value) { return $ret; } - - function del_config($family,$key) { - global $a; - if(x($a->config[$family],$key)) + if(array_key_exists($family,$a->config) && array_key_exists($key,$a->config[$family])) unset($a->config[$family][$key]); - $ret = q("DELETE FROM `config` WHERE `cat` = '%s' AND `k` = '%s' LIMIT 1", + $ret = q("DELETE FROM config WHERE cat = '%s' AND k = '%s' LIMIT 1", dbesc($family), dbesc($key) ); @@ -127,21 +122,40 @@ function del_config($family,$key) { } -function load_pconfig($uid,$family) { +function load_pconfig($uid,$family = '') { global $a; - $r = q("SELECT * FROM `pconfig` WHERE `cat` = '%s' AND `uid` = %d", - dbesc($family), - intval($uid) - ); - if(count($r)) { + + if($uid === false) + return false; + + if(! array_key_exists($uid,$a->config)) + $a->config[$uid] = array(); + if(($family) && (! array_key_exists($family,$a->config[$uid]))) + $a->config[$uid][$family] = array(); + + if($family) { + $r = q("SELECT * FROM `pconfig` WHERE `cat` = '%s' AND `uid` = %d", + dbesc($family), + intval($uid) + ); + } + else { + $r = q("SELECT * FROM `pconfig` WHERE `uid` = %d", + intval($uid) + ); + } + + if($r) { foreach($r as $rr) { $k = $rr['k']; - $a->config[$uid][$family][$k] = $rr['v']; + $c = $rr['cat']; + if(! array_key_exists($c,$a->config[$uid])) { + $a->config[$uid][$c] = array(); + $a->config[$uid][$c]['config_loaded'] = true; + } + $a->config[$uid][$c][$k] = $rr['v']; } - } else if ($family != 'config') { - // Negative caching - $a->config[$uid][$family] = "!<unset>!"; - } + } } @@ -151,74 +165,77 @@ function get_pconfig($uid,$family, $key, $instore = false) { global $a; - if(! $instore) { - // Looking if the whole family isn't set - if(isset($a->config[$uid][$family])) { - if($a->config[$uid][$family] === '!<unset>!') { - return false; - } - } + if($uid === false) + return false; - if(isset($a->config[$uid][$family][$key])) { - if($a->config[$uid][$family][$key] === '!<unset>!') { - return false; - } - return $a->config[$uid][$family][$key]; - } - } + if(! array_key_exists($uid,$a->config)) + load_pconfig($uid); - $ret = q("SELECT `v` FROM `pconfig` WHERE `uid` = %d AND `cat` = '%s' AND `k` = '%s' LIMIT 1", - intval($uid), - dbesc($family), - dbesc($key) - ); + if((! array_key_exists($family,$a->config[$uid])) || (! array_key_exists($key,$a->config[$uid][$family]))) + return false; - if(count($ret)) { - $val = (preg_match("|^a:[0-9]+:{.*}$|s", $ret[0]['v'])?unserialize( $ret[0]['v']):$ret[0]['v']); - $a->config[$uid][$family][$key] = $val; - return $val; - } - else { - $a->config[$uid][$family][$key] = '!<unset>!'; - } - return false; + return ((preg_match('|^a:[0-9]+:{.*}$|s', $a->config[$uid][$family][$key])) + ? unserialize($a->config[$uid][$family][$key]) + : $a->config[$uid][$family][$key] + ); } +function set_pconfig($uid,$family,$key,$value) { + global $a; + // manage array value + $dbvalue = ((is_array($value)) ? serialize($value) : $value); + $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue); -// Same as above functions except these are for personal config storage and take an -// additional $uid argument. - - -function set_pconfig($uid,$family,$key,$value) { + if(get_pconfig($uid,$family,$key) === false) { + if(! array_key_exists($uid,$a->config)) + $a->config[$uid] = array(); + if(! array_key_exists($family,$a->config[$uid])) + $a->config[$uid][$family] = array(); - global $a; + // keep a separate copy for all variables which were + // set in the life of this page. We need this to + // synchronise channel clones. - // manage array value - $dbvalue = (is_array($value)?serialize($value):$value); + if(! array_key_exists('transient',$a->config[$uid])) + $a->config[$uid]['transient'] = array(); + if(! array_key_exists($family,$a->config[$uid]['transient'])) + $a->config[$uid]['transient'][$family] = array(); - if(get_pconfig($uid,$family,$key,true) === false) { $a->config[$uid][$family][$key] = $value; - $ret = q("INSERT INTO `pconfig` ( `uid`, `cat`, `k`, `v` ) VALUES ( %d, '%s', '%s', '%s' ) ", + $a->config[$uid]['transient'][$family][$key] = $value; + + $ret = q("INSERT INTO pconfig ( uid, cat, k, v ) VALUES ( %d, '%s', '%s', '%s' ) ", intval($uid), dbesc($family), dbesc($key), dbesc($dbvalue) ); - if($ret) + if($ret) return $value; return $ret; } - $ret = q("UPDATE `pconfig` SET `v` = '%s' WHERE `uid` = %d AND `cat` = '%s' AND `k` = '%s' LIMIT 1", + + $ret = q("UPDATE pconfig SET v = '%s' WHERE uid = %d and cat = '%s' AND k = '%s' LIMIT 1", dbesc($dbvalue), intval($uid), dbesc($family), dbesc($key) ); + // keep a separate copy for all variables which were + // set in the life of this page. We need this to + // synchronise channel clones. + + if(! array_key_exists('transient',$a->config[$uid])) + $a->config[$uid]['transient'] = array(); + if(! array_key_exists($family,$a->config[$uid]['transient'])) + $a->config[$uid]['transient'][$family] = array(); + $a->config[$uid][$family][$key] = $value; + $a->config[$uid]['transient'][$family][$key] = $value; if($ret) return $value; @@ -231,7 +248,7 @@ function del_pconfig($uid,$family,$key) { global $a; if(x($a->config[$uid][$family],$key)) unset($a->config[$uid][$family][$key]); - $ret = q("DELETE FROM `pconfig` WHERE `uid` = %d AND `cat` = '%s' AND `k` = '%s' LIMIT 1", + $ret = q("DELETE FROM pconfig WHERE uid = %d AND cat = '%s' AND k = '%s' LIMIT 1", intval($uid), dbesc($family), dbesc($key) @@ -241,61 +258,64 @@ function del_pconfig($uid,$family,$key) { -function load_xconfig($xchan,$family) { +function load_xconfig($xchan,$family = '') { global $a; - $r = q("SELECT * FROM `xconfig` WHERE `cat` = '%s' AND `xchan` = '%s'", - dbesc($family), - dbesc($xchan) - ); - if(count($r)) { + + if(! $xchan) + return false; + + if(! array_key_exists($xchan,$a->config)) + $a->config[$xchan] = array(); + if(($family) && (! array_key_exists($family,$a->config[$xchan]))) + $a->config[$xchan][$family] = array(); + + if($family) { + $r = q("SELECT * FROM `xconfig` WHERE `cat` = '%s' AND `xchan` = '%s'", + dbesc($family), + dbesc($xchan) + ); + } + else { + $r = q("SELECT * FROM `xconfig` WHERE `xchan` = '%s'", + dbesc($xchan) + ); + } + + if($r) { foreach($r as $rr) { $k = $rr['k']; - $a->config[$xchan][$family][$k] = $rr['v']; + $c = $rr['cat']; + if(! array_key_exists($c,$a->config[$xchan])) { + $a->config[$xchan][$c] = array(); + $a->config[$xchan][$c]['config_loaded'] = true; + } + $a->config[$xchan][$c][$k] = $rr['v']; } - } else if ($family != 'config') { - // Negative caching - $a->config[$xchan][$family] = "!<unset>!"; - } + } + } -function get_xconfig($xchan,$family, $key, $instore = false) { +function get_xconfig($xchan,$family, $key) { global $a; - if(! $instore) { - // Looking if the whole family isn't set - if(isset($a->config[$xchan][$family])) { - if($a->config[$xchan][$family] === '!<unset>!') { - return false; - } - } + if(! $xchan) + return false; - if(isset($a->config[$xchan][$family][$key])) { - if($a->config[$xchan][$family][$key] === '!<unset>!') { - return false; - } - return $a->config[$xchan][$family][$key]; - } - } + if(! array_key_exists($xchan,$a->config)) + load_xconfig($xchan); - $ret = q("SELECT `v` FROM `xconfig` WHERE `xchan` = '%s' AND `cat` = '%s' AND `k` = '%s' LIMIT 1", - dbesc($xchan), - dbesc($family), - dbesc($key) + if((! array_key_exists($family,$a->config[$xchan])) || (! array_key_exists($key,$a->config[$xchan][$family]))) + return false; + + return ((preg_match('|^a:[0-9]+:{.*}$|s', $a->config[$xchan][$family][$key])) + ? unserialize($a->config[$xchan][$family][$key]) + : $a->config[$xchan][$family][$key] ); - if(count($ret)) { - $val = (preg_match("|^a:[0-9]+:{.*}$|s", $ret[0]['v'])?unserialize( $ret[0]['v']):$ret[0]['v']); - $a->config[$xchan][$family][$key] = $val; - return $val; - } - else { - $a->config[$xchan][$family][$key] = '!<unset>!'; - } - return false; } @@ -304,21 +324,28 @@ function set_xconfig($xchan,$family,$key,$value) { global $a; // manage array value - $dbvalue = (is_array($value)?serialize($value):$value); + $dbvalue = ((is_array($value)) ? serialize($value) : $value); + $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue); + + if(get_xconfig($xchan,$family,$key) === false) { + if(! array_key_exists($xchan,$a->config)) + $a->config[$xchan] = array(); + if(! array_key_exists($family,$a->config[$xchan])) + $a->config[$xchan][$family] = array(); - if(get_xconfig($xchan,$family,$key,true) === false) { $a->config[$xchan][$family][$key] = $value; - $ret = q("INSERT INTO `xconfig` ( `xchan`, `cat`, `k`, `v` ) VALUES ( '%s', '%s', '%s', '%s' ) ", + $ret = q("INSERT INTO xconfig ( xchan, cat, k, v ) VALUES ( '%s', '%s', '%s', '%s' ) ", dbesc($xchan), dbesc($family), dbesc($key), dbesc($dbvalue) ); - if($ret) + if($ret) return $value; return $ret; } - $ret = q("UPDATE `xconfig` SET `v` = '%s' WHERE `xchan` = '%s' AND `cat` = '%s' AND `k` = '%s' LIMIT 1", + + $ret = q("UPDATE xconfig SET v = '%s' WHERE xchan = '%s' and cat = '%s' AND k = '%s' LIMIT 1", dbesc($dbvalue), dbesc($xchan), dbesc($family), @@ -330,6 +357,7 @@ function set_xconfig($xchan,$family,$key,$value) { if($ret) return $value; return $ret; + } diff --git a/include/contact_selectors.php b/include/contact_selectors.php index adcca2c52..b56a77937 100644 --- a/include/contact_selectors.php +++ b/include/contact_selectors.php @@ -1,21 +1,19 @@ <?php /** @file */ -function contact_profile_assign($current,$foreign_net) { +function contact_profile_assign($current) { $o = ''; - $disabled = (($foreign_net) ? ' disabled="true" ' : ''); + $o .= "<select id=\"contact-profile-selector\" name=\"profile-assign\" />\r\n"; - $o .= "<select id=\"contact-profile-selector\" $disabled name=\"profile-assign\" />\r\n"; + $r = q("SELECT profile_guid, profile_name FROM `profile` WHERE `uid` = %d", + intval($_SESSION['uid'])); - $r = q("SELECT `id`, `profile_name` FROM `profile` WHERE `uid` = %d", - intval($_SESSION['uid'])); - - if(count($r)) { + if($r) { foreach($r as $rr) { - $selected = (($rr['id'] == $current) ? " selected=\"selected\" " : ""); - $o .= "<option value=\"{$rr['id']}\" $selected >{$rr['profile_name']}</option>\r\n"; + $selected = (($rr['profile_guid'] == $current) ? " selected=\"selected\" " : ""); + $o .= "<option value=\"{$rr['profile_guid']}\" $selected >{$rr['profile_name']}</option>\r\n"; } } $o .= "</select>\r\n"; diff --git a/include/conversation.php b/include/conversation.php index 13f67c4dd..1023c068d 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -6,7 +6,7 @@ require_once('include/items.php'); // is identical to the code in mod/message.php for 'item_extract_images' and // 'item_redir_and_replace_images' -if(! function_exists('item_extract_images')) { + function item_extract_images($body) { $saved_image = array(); @@ -46,9 +46,9 @@ function item_extract_images($body) { $new_body = $new_body . $orig_body; return array('body' => $new_body, 'images' => $saved_image); -}} +} + -if(! function_exists('item_redir_and_replace_images')) { function item_redir_and_replace_images($body, $images, $cid) { $origbody = $body; @@ -81,7 +81,7 @@ function item_redir_and_replace_images($body, $images, $cid) { } return $newbody; -}} +} @@ -108,6 +108,44 @@ function localize_item(&$item){ $item_url = get_rel_link($obj['link'],'alternate'); + $Bphoto = ''; + + switch($obj->type) { + case ACTIVITY_OBJ_PHOTO: + $post_type = t('photo'); + break; + case ACTIVITY_OBJ_EVENT: + $post_type = t('event'); + break; + case ACTIVITY_OBJ_PERSON: + $post_type = t('channel'); + $author_name = $obj['title']; + if($obj['link']) { + $author_link = get_rel_link($obj['link'],'alternate'); + $Bphoto = get_rel_link($obj['link'],'photo'); + } + break; + case ACTIVITY_OBJ_THING: + $post_type = $obj['title']; + if($obj['owner']) { + if(array_key_exists('name',$obj['owner'])) + $obj['owner']['name']; + if(array_key_exists('link',$obj['owner'])) + $author_link = get_rel_link($obj['owner']['link'],'alternate'); + } + if($obj['link']) { + $Bphoto = get_rel_link($obj['link'],'photo'); + } + break; + + case ACTIVITY_OBJ_NOTE: + default: + $post_type = t('status'); + if($obj->id != $item['mid']) + $post_type = t('comment'); + break; + } + // If we couldn't parse something useful, don't bother translating. // We need something better than zid here, probably magic_link(), but it needs writing @@ -117,21 +155,6 @@ function localize_item(&$item){ $author = '[zrl=' . chanlink_url($item['author']['xchan_url']) . ']' . $item['author']['xchan_name'] . '[/zrl]'; $objauthor = '[zrl=' . chanlink_url($author_link) . ']' . $author_name . '[/zrl]'; - switch($obj->type) { - case ACTIVITY_OBJ_PHOTO: - $post_type = t('photo'); - break; - case ACTIVITY_OBJ_EVENT: - $post_type = t('event'); - break; - case ACTIVITY_OBJ_NOTE: - default: - $post_type = t('status'); - if($obj->id != $item['mid']) - $post_type = t('comment'); - break; - } - $plink = '[zrl=' . zid($item_url) . ']' . $post_type . '[/zrl]'; if(activity_match($item['verb'],ACTIVITY_LIKE)) { @@ -141,6 +164,8 @@ function localize_item(&$item){ $bodyverb = t('%1$s doesn\'t like %2$s\'s %3$s'); } $item['body'] = $item['localize'] = sprintf($bodyverb, $author, $objauthor, $plink); + if($Bphoto != "") + $item['body'] .= "\n\n\n" . '[zrl=' . chanlink_url($author_link) . '][zmg=80x80]' . $Bphoto . '[/zmg][/zrl]'; } @@ -148,7 +173,8 @@ function localize_item(&$item){ if (activity_match($item['verb'],ACTIVITY_FRIEND)) { - if ($item['obj_type']=="" || $item['obj_type']!== ACTIVITY_OBJ_PERSON) return; + +// if ($item['obj_type']=="" || $item['obj_type']!== ACTIVITY_OBJ_PERSON) return; $Aname = $item['author']['xchan_name']; $Alink = $item['author']['xchan_url']; @@ -349,7 +375,9 @@ function count_descendants($item) { function visible_activity($item) { - if(activity_match($item['verb'],ACTIVITY_LIKE) || activity_match($item['verb'],ACTIVITY_DISLIKE)) + // likes can apply to other things besides posts. Check if they are post children, in which case we handle them specially + + if((activity_match($item['verb'],ACTIVITY_LIKE) || activity_match($item['verb'],ACTIVITY_DISLIKE)) && ($item['mid'] != $item['parent_mid'])) return false; return true; } @@ -365,7 +393,7 @@ function visible_activity($item) { * */ -if(!function_exists('conversation')) { + function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional') { $tstart = dba_timer(); @@ -374,6 +402,8 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional') { $ssl_state = ((local_user()) ? true : false); + if(local_user()) + load_pconfig(local_user(),''); $arr_blocked = null; @@ -554,17 +584,6 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional') { $tags=array(); $hashtags = array(); $mentions = array(); - foreach(explode(',',$item['tag']) as $tag){ - $tag = trim($tag); - if ($tag!="") { - $t = bbcode($tag); - $tags[] = $t; - if($t[0] == '#') - $hashtags[] = $t; - elseif($t[0] == '@') - $mentions[] = $t; - } - } $sp = false; $profile_link = best_link_url($item,$sp); @@ -620,7 +639,6 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional') { $tmp_item = array( 'template' => $tpl, 'toplevel' => 'toplevel_item', - 'tags' => $tags, 'id' => (($preview) ? 'P0' : $item['item_id']), 'linktitle' => sprintf( t('View %s\'s profile @ %s'), $profile_name, $profile_url), 'profile_url' => $profile_link, @@ -678,6 +696,7 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional') { } else { + // Normal View // logger('conv: items: ' . print_r($items,true)); @@ -790,7 +809,7 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional') { return $o; -}} +} function best_link_url($item) { @@ -823,7 +842,7 @@ function best_link_url($item) { } -if(! function_exists('item_photo_menu')){ + function item_photo_menu($item){ $a = get_app(); $contact = null; @@ -890,9 +909,9 @@ function item_photo_menu($item){ elseif ($v!="") $o .= "<li><a href=\"$v\">$k</a></li>\n"; } return $o; -}} +} + -if(! function_exists('like_puller')) { function like_puller($a,$item,&$arr,$mode) { $url = ''; @@ -920,7 +939,7 @@ function like_puller($a,$item,&$arr,$mode) { $arr[$item['thr_parent'] . '-l'][] = '<a href="'. $url . '"'. $sparkle .'>' . $item['author']['xchan_name'] . '</a>'; } return; -}} +} // Format the like/dislike text for a profile item // $cnt = number of people who like/dislike the item @@ -929,7 +948,7 @@ function like_puller($a,$item,&$arr,$mode) { // $id = item id // returns formatted text -if(! function_exists('format_like')) { + function format_like($cnt,$arr,$type,$id) { $o = ''; if($cnt == 1) @@ -953,7 +972,7 @@ function format_like($cnt,$arr,$type,$id) { $o .= "\t" . '<div id="' . $type . 'list-' . $id . '" style="display: none;" >' . $str . '</div>'; } return $o; -}} +} function status_editor($a,$x,$popup=false) { diff --git a/include/deliver.php b/include/deliver.php index c5ed35c87..547d009cc 100644 --- a/include/deliver.php +++ b/include/deliver.php @@ -23,11 +23,14 @@ function deliver_run($argv, $argc) { if($r[0]['outq_posturl'] === z_root() . '/post') { // local delivery // we should probably batch these and save a few delivery processes - $msg = array('body' => json_encode(array('pickup' => array(array('notify' => json_decode($r[0]['outq_notify'],true),'message' => json_decode($r[0]['outq_msg'],true)))))); - zot_import($msg); - $r = q("delete from outq where outq_hash = '%s' limit 1", - dbesc($argv[$x]) - ); + // If there is no outq_msg, this is a refresh_all message which does not require local handling + if($r[0]['outq_msg']) { + $msg = array('body' => json_encode(array('pickup' => array(array('notify' => json_decode($r[0]['outq_notify'],true),'message' => json_decode($r[0]['outq_msg'],true)))))); + zot_import($msg); + $r = q("delete from outq where outq_hash = '%s' limit 1", + dbesc($argv[$x]) + ); + } } else { $result = zot_zot($r[0]['outq_posturl'],$r[0]['outq_notify']); diff --git a/include/dir_fns.php b/include/dir_fns.php index 5a1d671cb..0b678fd91 100644 --- a/include/dir_fns.php +++ b/include/dir_fns.php @@ -53,7 +53,7 @@ function syncdirs($uid) { logger('syncdirs', LOGGER_DEBUG); - $p = q("select channel.channel_hash, profile.* from profile left join channel on channel_id = uid where uid = %d and is_default = 1", + $p = q("select channel.channel_hash, channel_timezone, profile.* from profile left join channel on channel_id = uid where uid = %d and is_default = 1", intval($uid) ); @@ -64,6 +64,9 @@ function syncdirs($uid) { $profile['description'] = $p[0]['pdesc']; $profile['birthday'] = $p[0]['dob']; + if($age = age($p[0]['dob'],$p[0]['channel_timezone'],'')) + $profile['age'] = $age; + $profile['gender'] = $p[0]['gender']; $profile['marital'] = $p[0]['marital']; $profile['sexual'] = $p[0]['sexual']; diff --git a/include/directory.php b/include/directory.php index 5f24b4af8..c286f5683 100644 --- a/include/directory.php +++ b/include/directory.php @@ -19,11 +19,6 @@ function directory_run($argv, $argc){ if($dirmode === false) $dirmode = DIRECTORY_MODE_NORMAL; - if(($dirmode == DIRECTORY_MODE_PRIMARY) || ($dirmode == DIRECTORY_MODE_STANDALONE)) { - syncdirs($argv[1]); - return; - } - $x = q("select * from channel where channel_id = %d limit 1", intval($argv[1]) ); @@ -32,6 +27,15 @@ function directory_run($argv, $argc){ $channel = $x[0]; + + if(($dirmode == DIRECTORY_MODE_PRIMARY) || ($dirmode == DIRECTORY_MODE_STANDALONE)) { + syncdirs($argv[1]); + + // Now update all the connections + proc_run('php','include/notifier.php','refresh_all',$channel['channel_id']); + return; + } + $directory = find_upstream_directory($dirmode); if($directory) { @@ -41,11 +45,16 @@ function directory_run($argv, $argc){ $url = DIRECTORY_FALLBACK_MASTER . '/post'; } + // ensure the upstream directory is updated + $packet = zot_build_packet($channel,'refresh'); $z = zot_zot($url,$packet); - // re-queue if unsuccessful + // Now update all the connections + + proc_run('php','include/notifier.php','refresh_all',$channel['channel_id']); + } if (array_search(__file__,get_included_files())===0){ diff --git a/include/enotify.php b/include/enotify.php index 5728d054c..3b7a643ed 100644 --- a/include/enotify.php +++ b/include/enotify.php @@ -50,6 +50,8 @@ function notification($params) { $additional_mail_header = ""; + // We really should pass this through localize_item - but only if we have a complete item. We may only have a couple of elements. + if(array_key_exists('item',$params)) { $title = $params['item']['title']; $body = $params['item']['body']; @@ -352,10 +354,27 @@ function notification($params) { logger('notification: sending notification email'); + $textversion = strip_tags(html_entity_decode(bbcode(stripslashes(str_replace(array("\\r\\n", "\\r", "\\n"), "\n", $body))),ENT_QUOTES,'UTF-8')); + $htmlversion = html_entity_decode(bbcode(stripslashes(str_replace(array("\\r\\n", "\\r","\\n\\n" ,"\\n"), - "<br />\n",$body)))); + "<br />\n",$body))), ENT_QUOTES,'UTF-8'); + + + // use $_SESSION['zid_override'] to force zid() to use + // the recipient address instead of the current observer + + $_SESSION['zid_override'] = $recip['channel_address'] . '@' . get_app()->get_hostname(); + $_SESSION['zrl_override'] = z_root() . '/channel/' . $recip['channel_address']; + + $textversion = zidify_links($textversion); + $htmlversion = zidify_links($htmlversion); + + // unset when done to revert to normal behaviour + + unset($_SESSION['zid_override']); + unset($_SESSION['zrl_override']); $datarray = array(); diff --git a/include/features.php b/include/features.php index c2aabbc42..da1322a14 100644 --- a/include/features.php +++ b/include/features.php @@ -58,6 +58,7 @@ function get_features() { array('filing', t('Saved Folders'), t('Ability to file posts under folders')), array('dislike', t('Dislike Posts'), t('Ability to dislike posts/comments')), array('star_posts', t('Star Posts'), t('Ability to mark special posts with a star indicator')), + array('tagadelic', t('Tag Cloud'), t('Provide a personal tag cloud on your channel page')), ), ); diff --git a/include/items.php b/include/items.php index 5489fa9e8..898fc9ff8 100755 --- a/include/items.php +++ b/include/items.php @@ -49,10 +49,46 @@ function collect_recipients($item,&$private) { $recipients = check_list_permissions($item['uid'],$recipients,'view_stream'); + // add ourself just in case we have nomadic clones that need to get a copy. + + $recipients[] = $item['author_xchan']; + if($item['owner_xchan'] != $item['author_xchan']) + $recipients[] = $item['owner_xchan']; return $recipients; } + +function can_comment_on_post($observer_xchan,$item) { + if(! $observer_xchan) + return false; + if($item['comment_policy'] === 'none') + return false; + switch($item['comment_policy']) { + case 'self': + if($observer_xchan === $item['author_xchan'] || $observer_xchan === $item['owner_xchan']) + return true; + break; + case 'public': + return false; + break; + case 'contacts': + case '': + if(($item['owner']['abook_xchan']) && ($item['owner']['abook_their_perms'] & PERMS_W_COMMENT)) + return true; + break; + default: + break; + } + if(strstr($item['comment_policy'],'network:') && strstr($item['comment_policy'],'red')) + return true; + if(strstr($item['comment_policy'],'site:') && strstr($item['comment_policy'],get_app()->get_hostname())) + return true; + + return false; +} + + /** * @function red_zrl_callback * preg_match function when fixing 'naked' links in mod item.php @@ -142,6 +178,7 @@ function post_activity_item($arr) { $arr['deny_cid'] = ((x($arr,'deny_cid')) ? $arr['deny_cid'] : $channel['channel_deny_cid']); $arr['deny_gid'] = ((x($arr,'deny_gid')) ? $arr['deny_gid'] : $channel['channel_deny_gid']); + $arr['comment_policy'] = map_scope($channel['channel_w_comment']); // for the benefit of plugins, we will behave as if this is an API call rather than a normal online post @@ -481,7 +518,8 @@ function get_item_elements($x) { $arr['mimetype'] = (($x['mimetype']) ? htmlentities($x['mimetype'], ENT_COMPAT,'UTF-8',false) : ''); $arr['obj_type'] = (($x['object_type']) ? htmlentities($x['object_type'], ENT_COMPAT,'UTF-8',false) : ''); $arr['tgt_type'] = (($x['target_type']) ? htmlentities($x['target_type'], ENT_COMPAT,'UTF-8',false) : ''); - + $arr['comment_policy'] = (($x['comment_scope']) ? htmlentities($x['comment_scope'], ENT_COMPAT,'UTF-8',false) : 'contacts'); + $arr['object'] = activity_sanitise($x['object']); $arr['target'] = activity_sanitise($x['target']); @@ -545,17 +583,21 @@ function encode_item($item) { logger('encode_item: ' . print_r($item,true)); - $r = q("select channel_r_stream from channel where channel_id = %d limit 1", + $r = q("select channel_r_stream, channel_w_comment from channel where channel_id = %d limit 1", intval($item['uid']) ); - if($r) + if($r) { $public_scope = $r[0]['channel_r_stream']; - else + $comment_scope = $r[0]['channel_w_comment']; + } + else { $public_scope = 0; + $comment_scope = 0; + } $scope = map_scope($public_scope); - + $c_scope = map_scope($comment_scope); if($item['item_restrict'] & ITEM_DELETED) { $x['message_id'] = $item['mid']; @@ -597,6 +639,11 @@ function encode_item($item) { if(! in_array('private',$y)) $x['public_scope'] = $scope; + if($item['item_flags'] & ITEM_NOCOMMENT) + $x['comment_scope'] = 'none'; + else + $x['comment_scope'] = $c_scope; + if($item['term']) $x['tags'] = encode_item_terms($item['term']); @@ -818,6 +865,7 @@ function get_profile_elements($x) { $arr['desc'] = (($x['title']) ? htmlentities($x['title'],ENT_COMPAT,'UTF-8',false) : ''); $arr['dob'] = datetime_convert('UTC','UTC',$x['birthday'],'Y-m-d'); + $arr['age'] = (($x['age']) ? intval($x['age']) : 0); $arr['gender'] = (($x['gender']) ? htmlentities($x['gender'], ENT_COMPAT,'UTF-8',false) : ''); $arr['marital'] = (($x['marital']) ? htmlentities($x['marital'], ENT_COMPAT,'UTF-8',false) : ''); @@ -1323,10 +1371,17 @@ function item_store($arr,$force_parent = false) { $arr['attach'] = ((x($arr,'attach')) ? notags(trim($arr['attach'])) : ''); $arr['app'] = ((x($arr,'app')) ? notags(trim($arr['app'])) : ''); $arr['item_restrict'] = ((x($arr,'item_restrict')) ? intval($arr['item_restrict']) : 0 ); + + $arr['comment_policy'] = ((x($arr,'comment_policy')) ? notags(trim($arr['comment_policy'])) : 'contacts' ); + $arr['item_flags'] = ((x($arr,'item_flags')) ? intval($arr['item_flags']) : 0 ); $arr['item_flags'] = $arr['item_flags'] | ITEM_UNSEEN; + if($arr['comment_policy'] == 'none') + $arr['item_flags'] = $arr['item_flags'] | ITEM_NOCOMMENT; + + // handle time travelers // Allow a bit of fudge in case somebody just has a slightly slow/fast clock @@ -1808,30 +1863,73 @@ function tag_deliver($uid,$item_id) { // See if we are the owner of the parent item and have given permission to tag our posts. // If so tag the parent post. - // FIXME --- If the item is deleted, remove the tag from the parent. - // (First ensure that deleted items use this function, or else do that part separately.) + logger('tag_deliver: community tag activity received'); if(($item['owner_xchan'] === $u[0]['channel_hash']) && (! get_pconfig($u[0]['channel_id'],'system','blocktags'))) { $j_tgt = json_decode($item['target'],true); - if($j_tgt && $j_tgt['mid']) { + if($j_tgt && $j_tgt['id']) { $p = q("select * from item where mid = '%s' and uid = %d limit 1", - dbesc($j_tgt['mid']), + dbesc($j_tgt['id']), intval($u[0]['channel_id']) ); if($p) { $j_obj = json_decode($item['object'],true); + logger('tag_deliver: tag object: ' . print_r($j_obj,true), LOGGER_DATA); if($j_obj && $j_obj['id'] && $j_obj['title']) { - store_item_tag($u[0]['channel_id'],$p[0]['id'],TERM_OBJ_POST,TERM_HASHTAG,$j_obj['title'],$j['obj']['id']); + if(is_array($j_obj['link'])) + $taglink = get_rel_link($j_obj['link'],'alternate'); + store_item_tag($u[0]['channel_id'],$p[0]['id'],TERM_OBJ_POST,TERM_HASHTAG,$j_obj['title'],$j_obj['id']); proc_run('php','include/notifier.php','edit_post',$p[0]['id']); } } } } + else + logger('tag_deliver: tag permission denied for ' . $u[0]['channel_address']); + } + + // This might be a followup by the original post author to a tagged forum + // If so setup a second delivery chain + + $r = null; + + if( ! ($item['item_flags'] & ITEM_THREAD_TOP)) { + $x = q("select * from item where id = parent and parent = %d and uid = %d limit 1", + intval($item['parent']), + intval($uid) + ); + if(($x) && ($x[0]['item_flags'] & ITEM_UPLINK) && ($x[0]['author_xchan'] == $item['author_xchan'])) { + logger('tag_deliver: creating second delivery chain for owner comment.'); + + // now change this copy of the post to a forum head message and deliver to all the tgroup members + // also reset all the privacy bits to the forum default permissions + + $private = (($u[0]['allow_cid'] || $u[0]['allow_gid'] || $u[0]['deny_cid'] || $u[0]['deny_gid']) ? 1 : 0); + + $flag_bits = ITEM_WALL|ITEM_ORIGIN; + + $r = q("update item set item_flags = ( item_flags | %d ), owner_xchan = '%s', allow_cid = '%s', allow_gid = '%s', + deny_cid = '%s', deny_gid = '%s', item_private = %d where id = %d limit 1", + intval($flag_bits), + dbesc($u[0]['channel_hash']), + dbesc($u[0]['allow_cid']), + dbesc($u[0]['allow_gid']), + dbesc($u[0]['deny_cid']), + dbesc($u[0]['deny_gid']), + intval($private), + intval($item_id) + ); + if($r) + proc_run('php','include/notifier.php','tgroup',$item_id); + else + logger('tag_deliver: failed to update item'); + } } $terms = get_terms_oftype($item['term'],TERM_MENTION); - logger('tag_deliver: post mentions: ' . print_r($terms,true), LOGGER_DATA); + if($terms) + logger('tag_deliver: post mentions: ' . print_r($terms,true), LOGGER_DATA); $link = normalise_link($a->get_baseurl() . '/channel/' . $u[0]['channel_address']); @@ -1931,45 +2029,51 @@ function tgroup_check($uid,$item) { // check that the message originated elsewhere and is a top-level post - if(($item['wall']) || ($item['origin']) || ($item['mid'] != $item['parent-mid'])) + if($arr['mid'] != $arr['parent_mid']) return false; + if(! perm_is_allowed($uid,$item['author_xchan'],'tag_deliver')) + return false; - $u = q("select * from user where uid = %d limit 1", + $u = q("select * from channel where channel_id = %d limit 1", intval($uid) ); - if(! count($u)) - return false; - - $community_page = (($u[0]['page-flags'] == PAGE_COMMUNITY) ? true : false); - $prvgroup = (($u[0]['page-flags'] == PAGE_PRVGROUP) ? true : false); + if(! $u) + return false; - $link = normalise_link($a->get_baseurl() . '/channel/' . $u[0]['nickname']); + $terms = get_terms_oftype($item['term'],TERM_MENTION); - // Diaspora uses their own hardwired link URL in @-tags - // instead of the one we supply with webfinger + logger('tgroup_check: post mentions: ' . print_r($terms,true), LOGGER_DATA); - $dlink = normalise_link($a->get_baseurl() . '/u/' . $u[0]['nickname']); + $link = normalise_link($a->get_baseurl() . '/channel/' . $u[0]['channel_address']); - $body = preg_replace("/\[share\](.*?)\[\/share\]/ism", '', $item['body']); - - $cnt = preg_match_all('/[\@\!]\[zrl\=(.*?)\](.*?)\[\/zrl\]/ism',$body,$matches,PREG_SET_ORDER); - if($cnt) { - foreach($matches as $mtch) { - if(link_compare($link,$mtch[1]) || link_compare($dlink,$mtch[1])) { + if($terms) { + foreach($terms as $term) { + if(($term['term'] == $u[0]['channel_name']) && link_compare($term['url'],$link)) { $mention = true; - logger('tgroup_check: mention found: ' . $mtch[2]); + break; } } - } + } - if(! $mention) + if($mention) { + logger('tgroup_check: mention found for ' . $u[0]['channel_name']); + } + else return false; - if((! $community_page) && (! $prvgroup)) - return false; + // At this point we've determined that the person receiving this post was mentioned in it. + // Now let's check if this mention was inside a reshare so we don't spam a forum + + $body = preg_replace('/\[share(.*?)\[\/share\]/','',$item['body']); + + $pattern = '/@\[zrl\=' . preg_quote($term['url'],'/') . '\]' . preg_quote($u[0]['channel_name'],'/') . '\[\/zrl\]/'; + if(! preg_match($pattern,$body,$matches)) { + logger('tgroup_check: mention was in a reshare - ignoring'); + return false; + } return true; @@ -4684,7 +4788,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C intval($uid) ); if($r) { - $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND uid = " . intval($arr['uid']) . " AND ( author_xchan = " . dbesc($r[0]['abook_xchan']) . " or owner_xchan = " . dbesc($r[0]['abook_xchan']) . " ) and item_restrict = 0 ) "; + $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND uid = " . intval($arr['uid']) . " AND ( author_xchan = '" . dbesc($r[0]['abook_xchan']) . "' or owner_xchan = '" . dbesc($r[0]['abook_xchan']) . "' ) and item_restrict = 0 ) "; } else { $result['message'] = t('Connection not found.'); diff --git a/include/network.php b/include/network.php index f750fcfd8..8b9a8a6a6 100644 --- a/include/network.php +++ b/include/network.php @@ -1049,15 +1049,21 @@ function scale_external_images($s, $include_link = true, $scale_replace = false) $s = htmlspecialchars_decode($s); $matches = null; - $c = preg_match_all('/\[img.*?\](.*?)\[\/img\]/ism',$s,$matches,PREG_SET_ORDER); + $c = preg_match_all('/\[img(.*?)\](.*?)\[\/img\]/ism',$s,$matches,PREG_SET_ORDER); if($c) { require_once('include/photo/photo_driver.php'); foreach($matches as $mtch) { - logger('scale_external_image: ' . $mtch[1]); + logger('scale_external_image: ' . $mtch[1] . ' ' . $mtch[2]); + + if(substr($mtch[1],0,1) == '=') { + $owidth = intval(substr($mtch[1],1)); + if(intval($owidth) > 0 && intval($owidth) < 640) + continue; + } $hostname = str_replace('www.','',substr($a->get_baseurl(),strpos($a->get_baseurl(),'://')+3)); - if(stristr($mtch[1],$hostname)) + if(stristr($mtch[2],$hostname)) continue; // $scale_replace, if passed, is an array of two elements. The @@ -1066,9 +1072,9 @@ function scale_external_images($s, $include_link = true, $scale_replace = false) // This allows Friendica to display the smaller remote image if // one exists, while still linking to the full-size image if($scale_replace) - $scaled = str_replace($scale_replace[0], $scale_replace[1], $mtch[1]); + $scaled = str_replace($scale_replace[0], $scale_replace[1], $mtch[2]); else - $scaled = $mtch[1]; + $scaled = $mtch[2]; $i = fetch_url($scaled); $cache = get_config('system','itemcache'); @@ -1078,7 +1084,7 @@ function scale_external_images($s, $include_link = true, $scale_replace = false) } // guess mimetype from headers or filename - $type = guess_image_type($mtch[1],true); + $type = guess_image_type($mtch[2],true); if($i) { $ph = photo_factory($i, $type); @@ -1094,7 +1100,7 @@ function scale_external_images($s, $include_link = true, $scale_replace = false) logger('scale_external_images: ' . $orig_width . '->' . $new_width . 'w ' . $orig_height . '->' . $new_height . 'h' . ' match: ' . $mtch[0], LOGGER_DEBUG); $s = str_replace($mtch[0],'[img=' . $new_width . 'x' . $new_height. ']' . $scaled . '[/img]' . "\n" . (($include_link) - ? '[zrl=' . $mtch[1] . ']' . t('view full size') . '[/zrl]' . "\n" + ? '[zrl=' . $mtch[2] . ']' . t('view full size') . '[/zrl]' . "\n" : ''),$s); logger('scale_external_images: new string: ' . $s, LOGGER_DEBUG); } diff --git a/include/notifier.php b/include/notifier.php index 159931124..96c0bf31f 100644 --- a/include/notifier.php +++ b/include/notifier.php @@ -53,6 +53,7 @@ require_once('include/html2plain.php'); * * ZOT * permission_update abook_id + * refresh_all channel_id * relay item_id (item was relayed to owner, we will deliver it as owner) * */ @@ -136,6 +137,7 @@ function notifier_run($argv, $argc){ $recipients = array(); $url_recipients = array(); $normal_mode = true; + $packet_type = 'undefined'; if($cmd === 'mail') { $normal_mode = false; @@ -186,6 +188,27 @@ function notifier_run($argv, $argc){ $recipients[] = $suggest[0]['cid']; $item = $suggest[0]; } + elseif($cmd === 'refresh_all') { + logger('notifier: refresh_all: ' . $item_id); + $s = q("select * from channel where channel_id = %d limit 1", + intval($item_id) + ); + if($s) + $channel = $s[0]; + $uid = $item_id; + $recipients = array(); + $r = q("select * from abook where abook_channel = %d and not (abook_flags & %d)", + intval($item_id), + intval(ABOOK_FLAG_SELF) + ); + if($r) { + foreach($r as $rr) { + $recipients[] = $rr['abook_xchan']; + } + } + $private = false; + $packet_type = 'refresh'; + } else { // Normal items @@ -213,6 +236,12 @@ function notifier_run($argv, $argc){ return; } + if($target_item['item_restrict'] & ITEM_WEBPAGE) { + logger('notifier: target item ITEM_WEBPAGE', LOGGER_DEBUG); + return; + } + + $s = q("select * from channel where channel_id = %d limit 1", intval($target_item['uid']) ); @@ -346,18 +375,34 @@ function notifier_run($argv, $argc){ foreach($hubs as $hub) { $hash = random_string(); - $n = zot_build_packet($channel,'notify',$env_recips,(($private) ? $hub['hubloc_sitekey'] : null),$hash); - 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' )", - dbesc($hash), - intval($target_item['aid']), - intval($target_item['uid']), - dbesc($hub['hubloc_callback']), - intval(1), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc($n), - dbesc(json_encode($encoded_item)) - ); + if($packet_type === 'refresh') { + $n = zot_build_packet($channel,'refresh'); + 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' )", + dbesc($hash), + intval($channel['channel_account']), + intval($channel['channel_id']), + dbesc($hub['hubloc_callback']), + intval(1), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + dbesc($n), + dbesc('') + ); + } + else { + $n = zot_build_packet($channel,'notify',$env_recips,(($private) ? $hub['hubloc_sitekey'] : null),$hash); + 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' )", + dbesc($hash), + intval($target_item['aid']), + intval($target_item['uid']), + dbesc($hub['hubloc_callback']), + intval(1), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + dbesc($n), + dbesc(json_encode($encoded_item)) + ); + } $deliver[] = $hash; if(count($deliver) >= $deliveries_per_process) { diff --git a/include/permissions.php b/include/permissions.php index 071a599f8..bf380cf95 100644 --- a/include/permissions.php +++ b/include/permissions.php @@ -98,7 +98,7 @@ function get_all_perms($uid,$observer_xchan,$internal_use = true) { // If they're blocked - they can't read or write - if(($x) && (($x[0]['abook_flags'] & ABOOK_FLAG_BLOCKED) || ($x[0]['abook_flags'] & ABOOK_FLAG_PENDING))) { + if(($x) && ($x[0]['abook_flags'] & ABOOK_FLAG_BLOCKED)) { $ret[$perm_name] = false; continue; } @@ -164,13 +164,17 @@ function get_all_perms($uid,$observer_xchan,$internal_use = true) { // If PERMS_CONTACTS or PERMS_SPECIFIC, they need to be in your address book // $x is a valid address book entry - - if(! $x) { $ret[$perm_name] = false; continue; } + // They are in your address book, but haven't been approved + + if($x[0]['abook_flags'] & ABOOK_FLAG_PENDING) { + $ret[$perm_name] = false; + continue; + } if(($r) && ($r[0][$channel_perm] & PERMS_CONTACTS)) { @@ -242,7 +246,7 @@ function perm_is_allowed($uid,$observer_xchan,$permission) { // If they're blocked - they can't read or write - if(($x) && (($x[0]['abook_flags'] & ABOOK_FLAG_BLOCKED) || ($x[0]['abook_flags'] & ABOOK_FLAG_PENDING))) + if(($x) && ($x[0]['abook_flags'] & ABOOK_FLAG_BLOCKED)) return false; if(($x) && (! $global_perms[$permission][2]) && ($x[0]['abook_flags'] & ABOOK_FLAG_IGNORED)) @@ -287,6 +291,10 @@ function perm_is_allowed($uid,$observer_xchan,$permission) { return false; } + if($x[0]['abook_flags'] & ABOOK_FLAG_PENDING) { + return false; + } + if($r[0][$channel_perm] & PERMS_CONTACTS) { return true; } diff --git a/include/poller.php b/include/poller.php index dff16d3d7..f50bd4e3e 100644 --- a/include/poller.php +++ b/include/poller.php @@ -63,6 +63,9 @@ function poller_run($argv, $argc){ // once daily run birthday_updates and then expire in background + // FIXME: add birthday updates, both locally and for xprof for use + // by directory servers + $d1 = get_config('system','last_expire_day'); $d2 = intval(datetime_convert('UTC','UTC','now','d')); diff --git a/include/profile_advanced.php b/include/profile_advanced.php index f008d1c8f..21606185d 100644 --- a/include/profile_advanced.php +++ b/include/profile_advanced.php @@ -80,9 +80,44 @@ function advanced_profile(&$a) { if($txt = prepare_text($a->profile['education'])) $profile['education'] = array( t('School/education:'), $txt ); + $r = q("select * from obj left join term on obj_obj = term_hash where term_hash != '' and obj_page = '%s' and uid = %d and obj_type = %d + order by obj_verb, term", + dbesc($a->profile['profile_guid']), + intval($a->profile['profile_uid']), + intval(TERM_OBJ_THING) + ); + + $things = null; + + if($r) { + $things = array(); + + // Use the system obj_verbs array as a sort key, since we don't really + // want an alphabetic sort. To change the order, use a plugin to + // alter the obj_verbs() array or alter it in code. Unknown verbs come + // after the known ones - in no particular order. + + $v = obj_verbs(); + foreach($v as $k => $foo) + $things[$k] = null; + foreach($r as $rr) { + if(! $things[$rr['obj_verb']]) + $things[$rr['obj_verb']] = array(); + $things[$rr['obj_verb']][] = array('term' => $rr['term'],'url' => $rr['url'],'img' => $rr['imgurl']); + } + $sorted_things = array(); + if($things) + foreach($things as $k => $v) + if(is_array($things[$k])) + $sorted_things[$k] = $v; + } + + logger('mod_profile: things: ' . print_r($sorted_things,true), LOGGER_DATA); + return replace_macros($tpl, array( '$title' => t('Profile'), '$profile' => $profile, + '$things' => $sorted_things )); } diff --git a/include/settings.php b/include/settings.php new file mode 100644 index 000000000..26f375a42 --- /dev/null +++ b/include/settings.php @@ -0,0 +1,99 @@ +<?php /** @file */ + +/** + * Send a zot packet to all hubs where this channel is duplicated, refreshing + * such things as personal settings, channel permissions, address book updates, etc. + */ + +require_once('include/zot.php'); + +function build_sync_packet($uid = 0, $packet = null) { + $a = get_app(); + + if(! $uid) + $uid = local_user(); + + if(! $uid) + return; + + $channel = $a->get_channel(); + + $h = q("select * from hubloc where hubloc_hash = '%s'", + dbesc($channel['channel_hash']) + ); + + if(! $h) + return; + + $synchubs = array(); + + foreach($h as $x) { + if($x['host'] == $a->get_hostname()) + continue; + $synchubs[] = $x; + } + + if(! $synchubs) + return; + + $r = q("select xchan_guid, xchan_guid_sig from xchan where xchan_hash = '%s' limit 1", + dbesc($channel['channel_hash']) + ); + if(! $r) + return; + + $env_recips = array(); + $env_recips[] = array('guid' => $r[0]['xchan_guid'],'guid_sig' => $r[0]['xchan_guid_sig']); + + $info = (($packet) ? $packet : array()); + + if(array_key_exists($uid,$a->config) && array_key_exists('transient',$a->config[$uid])) { + $settings = $a->config[$uid]['transient']; + if($settings) { + $info['config'] = $settings; + } + } + + if($channel) { + $info['channel'] = array(); + foreach($channel as $k => $v) { + if(strpos('channel_',$k) !== 0) + continue; + + // don't pass these elements, they should not be synchronised + + $disallowed = array('channel_id','channel_account_id','channel_primary','channel_prvkey'); + + if(in_array($k,$disallowed)) + continue; + + $info['channel'][$k] = $v; + } + } + + $interval = ((get_config('system','delivery_interval') !== false) + ? intval(get_config('system','delivery_interval')) : 2 ); + + + foreach($synchubs as $hub) { + $hash = random_string(); + $n = zot_build_packet($channel,'channel_sync',$env_recips,$hub['hubloc_sitekey'],null,$hash); + 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' )", + dbesc($hash), + intval($channel['channel_account']), + intval($channel['channel_id']), + dbesc($hub['hubloc_callback']), + intval(1), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + dbesc($n), + dbesc(json_encode($info)) + ); + + proc_run('php','include/deliver.php',$hash); + if($interval) + @time_sleep_until(microtime(true) + (float) $interval); + } + + +} diff --git a/include/taxonomy.php b/include/taxonomy.php new file mode 100644 index 000000000..b6803743a --- /dev/null +++ b/include/taxonomy.php @@ -0,0 +1,208 @@ +<?php /** @file */ + +// post categories and "save to file" use the same item.file table for storage. +// We will differentiate the different uses by wrapping categories in angle brackets +// and save to file categories in square brackets. +// To do this we need to escape these characters if they appear in our tag. + +function file_tag_encode($s) { + return str_replace(array('<','>','[',']'),array('%3c','%3e','%5b','%5d'),$s); +} + +function file_tag_decode($s) { + return str_replace(array('%3c','%3e','%5b','%5d'),array('<','>','[',']'),$s); +} + +function file_tag_file_query($table,$s,$type = 'file') { + + if($type == 'file') + $termtype = TERM_FILE; + else + $termtype = TERM_CATEGORY; + + return sprintf(" AND " . (($table) ? dbesc($table) . '.' : '') . "id in (select term.oid from term where term.type = %d and term.term = '%s' and term.uid = " . (($table) ? dbesc($table) . '.' : '') . "uid ) ", + intval($termtype), + protect_sprintf(dbesc($s)) + ); +} + +function term_query($table,$s,$type = TERM_UNKNOWN) { + + return sprintf(" AND " . (($table) ? dbesc($table) . '.' : '') . "id in (select term.oid from term where term.type = %d and term.term = '%s' and term.uid = " . (($table) ? dbesc($table) . '.' : '') . "uid ) ", + intval($type), + protect_sprintf(dbesc($s)) + ); +} + + +function store_item_tag($uid,$iid,$otype,$type,$term,$url = '') { + if(! $term) + return false; + $r = q("select * from term + where uid = %d and oid = %d and otype = %d and type = %d + and term = '%s' and url = '%s' ", + intval($uid), + intval($iid), + intval($otype), + intval($type), + dbesc($term), + dbesc($url) + ); + if($r) + return false; + $r = q("insert into term (uid, oid, otype, type, term, url) + values( %d, %d, %d, %d, '%s', '%s') ", + intval($uid), + intval($iid), + intval($otype), + intval($type), + dbesc($term), + dbesc($url) + ); + return $r; +} + +function get_terms_oftype($arr,$type) { + $ret = array(); + if(! (is_array($arr) && count($arr))) + return $ret; + + if(! is_array($type)) + $type = array($type); + + foreach($type as $t) + foreach($arr as $x) + if($x['type'] == $t) + $ret[] = $x; + return $ret; +} + +function format_term_for_display($term) { + $s = ''; + if($term['type'] == TERM_HASHTAG) + $s .= '#'; + elseif($term['type'] == TERM_MENTION) + $s .= '@'; + else + return $s; + + if($term['url']) + $s .= '<a href="' . $term['url'] . '">' . htmlspecialchars($term['term']) . '</a>'; + else + $s .= htmlspecialchars($term['term']); + return $s; +} + +// Tag cloud functions - need to be adpated to this database format + + +function tagadelic($uid, $count = 0, $authors = '', $flags = 0, $type = TERM_HASHTAG) { + + $sql_options = ''; + + if($flags) + $sql_options .= " and ((item_flags & " . intval($flags) . ") = " . intval($flags) . ") "; + if($authors) { + if(! is_array($authors)) + $authors = array($authors); + stringify_array_elms($authors,true); + $sql_options .= " and author_xchan in (" . implode(',',$authors) . ") "; + } + + // 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 + $sql_options + group by term order by total desc %s", + intval($uid), + intval($type), + intval(TERM_OBJ_POST), + ((intval($count)) ? "limit $count" : '') + ); + + if(! $r) + return array(); + + // Find minimum and maximum log-count. + $tags = array(); + $min = 1e9; + $max = -1e9; + + $x = 0; + foreach($r as $rr) { + $tags[$x][0] = $rr['term']; + $tags[$x][1] = log($rr['total']); + $tags[$x][2] = 0; + $min = min($min,$tags[$x][1]); + $max = max($max,$tags[$x][1]); + $x ++; + } + + usort($tags,'tags_sort'); + + $range = max(.01, $max - $min) * 1.0001; + + for($x = 0; $x < count($tags); $x ++) { + $tags[$x][2] = 1 + floor(5 * ($tags[$x][1] - $min) / $range); + } + + return $tags; +} + +function tags_sort($a,$b) { + if($a[0] == $b[0]) + return 0; + return((strtolower($a[0]) < strtolower($b[0])) ? -1 : 1); +} + + +function tagblock($link,$uid,$count = 0,$authors = '',$flags = 0,$type = TERM_HASHTAG) { + $o = ''; + $tab = 0; + $r = tagadelic($uid,$count,$authors,$flags,$type); + + if($r) { + $o = '<div class="tagblock widget"><h3>' . t('Tags') . '</h3><div class="tags" align="center">'; + foreach($r as $rr) { + $o .= '<a href="'.$link .'/' . '?f=&tag=' . urlencode($rr[0]).'" class="tag'.$rr[2].'">'.$rr[0].'</a> ' . "\r\n"; + } + $o .= '</div></div>'; + } + return $o; +} + + + /** + * verbs: [0] = first person singular, e.g. "I want", [1] = 3rd person singular, e.g. "Bill wants" + * We use the first person form when creating an activity, but the third person for use in activities + * FIXME: There is no accounting for verb gender for languages where this is significant. We may eventually + * require obj_verbs() to provide full conjugations and specify which form to use in the $_REQUEST params to this module. + */ + + + +function obj_verbs() { + $verbs = array( + 'has' => array( t('have'), t('has')), + 'wants' => array( t('want'), t('wants')), + 'likes' => array( t('like'), t('likes')), + 'dislikes' => array( t('dislike'), t('dislikes')), + ); + + $arr = array('verbs' => $verbs); + call_hooks('obj_verbs', $arr); + return $arr['verbs']; +} + + +function obj_verb_selector() { + $verbs = obj_verbs(); + $o .= '<select class="obj-verb-selector" name="verb" >'; + foreach($verbs as $k => $v) { + $o .= '<option value="' . urlencode($k) . '">' . $v[0] . '</option>'; + } + $o .= '</select>'; + return $o; + +}
\ No newline at end of file diff --git a/include/text.php b/include/text.php index 71f2257ac..2d29dff31 100755 --- a/include/text.php +++ b/include/text.php @@ -850,7 +850,6 @@ function smilies($s, $sample = false) { ':like', ':dislike', 'red#', - '~friendika', '~friendica' ); @@ -889,7 +888,6 @@ 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" />', '<img class="smiley" src="' . $a->get_baseurl() . '/images/rhash-16.png" alt="red#" /></a>', - '<a href="http://project.friendika.com">~friendika <img class="smiley" src="' . $a->get_baseurl() . '/images/friendika-16.png" alt="~friendika" /></a>', '<a href="http://friendica.com">~friendica <img class="smiley" src="' . $a->get_baseurl() . '/images/friendica-16.png" alt="~friendica" /></a>' ); @@ -1025,6 +1023,25 @@ function prepare_body($item,$attach = false) { $s .= '<div class="clear"></div></div>'; } +// At some point in time, posttags were removed from the threaded conversation templates, but remained in the search_item template. +// Code to put them back was added into include/conversation.php and/or include/ItemObject.php but under new class names +// Then it was discovered that the following bits remained of the old code. +// Commented out, but we may decide to use this instead of the other version and put all the tag rendering in one place. In the other +// location it is more theme-able. +// if(is_array($item['term']) && count($item['term'])) { +// $tstr = ''; +// foreach($item['term'] as $t) { +// $t1 = format_term_for_display($t); +// if($t1) { +// if($tstr) +// $tstr .= ' '; +// $tstr .= $t1; +// } +// } +// if($tstr) +// $s .= '<br /><div class="posttags">' . $tstr . '</div>'; +// } + $writeable = ((get_observer_hash() == $item['owner_xchan']) ? true : false); $x = ''; @@ -1424,278 +1441,28 @@ function reltoabs($text, $base) } function item_post_type($item) { - if(intval($item['event-id'])) - return t('event'); - if(strlen($item['resource_id'])) - return t('photo'); - if(strlen($item['verb']) && $item['verb'] !== ACTIVITY_POST) - return t('activity'); - if($item['id'] != $item['parent']) - return t('comment'); - return t('post'); -} - -// post categories and "save to file" use the same item.file table for storage. -// We will differentiate the different uses by wrapping categories in angle brackets -// and save to file categories in square brackets. -// To do this we need to escape these characters if they appear in our tag. - -function file_tag_encode($s) { - return str_replace(array('<','>','[',']'),array('%3c','%3e','%5b','%5d'),$s); -} - -function file_tag_decode($s) { - return str_replace(array('%3c','%3e','%5b','%5d'),array('<','>','[',']'),$s); -} - -function file_tag_file_query($table,$s,$type = 'file') { - - if($type == 'file') - $termtype = TERM_FILE; - else - $termtype = TERM_CATEGORY; - - return sprintf(" AND " . (($table) ? dbesc($table) . '.' : '') . "id in (select term.oid from term where term.type = %d and term.term = '%s' and term.uid = " . (($table) ? dbesc($table) . '.' : '') . "uid ) ", - intval($termtype), - protect_sprintf(dbesc($s)) - ); -} - -function term_query($table,$s,$type = TERM_UNKNOWN) { - - return sprintf(" AND " . (($table) ? dbesc($table) . '.' : '') . "id in (select term.oid from term where term.type = %d and term.term = '%s' and term.uid = " . (($table) ? dbesc($table) . '.' : '') . "uid ) ", - intval($type), - protect_sprintf(dbesc($s)) - ); -} - -// ex. given music,video return <music><video> or [music][video] -function file_tag_list_to_file($list,$type = 'file') { - $tag_list = ''; - if(strlen($list)) { - $list_array = explode(",",$list); - if($type == 'file') { - $lbracket = '['; - $rbracket = ']'; - } - else { - $lbracket = '<'; - $rbracket = '>'; - } - - foreach($list_array as $item) { - if(strlen($item)) { - $tag_list .= $lbracket . file_tag_encode(trim($item)) . $rbracket; - } - } - } - return $tag_list; -} - -// ex. given <music><video>[friends], return music,video or friends -function file_tag_file_to_list($file,$type = 'file') { - $matches = false; - $list = ''; - if($type == 'file') { - $cnt = preg_match_all('/\[(.*?)\]/',$file,$matches,PREG_SET_ORDER); - } - else { - $cnt = preg_match_all('/<(.*?)>/',$file,$matches,PREG_SET_ORDER); - } - if($cnt) { - foreach($matches as $mtch) { - if(strlen($list)) - $list .= ','; - $list .= file_tag_decode($mtch[1]); - } - } - - return $list; -} - -function file_tag_update_pconfig($uid,$file_old,$file_new,$type = 'file') { - // $file_old - categories previously associated with an item - // $file_new - new list of categories for an item - - if(! intval($uid)) - return false; - - if($file_old == $file_new) - return true; - - $saved = get_pconfig($uid,'system','filetags'); - if(strlen($saved)) { - if($type == 'file') { - $lbracket = '['; - $rbracket = ']'; - } - else { - $lbracket = '<'; - $rbracket = '>'; - } - - $filetags_updated = $saved; - - // check for new tags to be added as filetags in pconfig - $new_tags = array(); - $check_new_tags = explode(",",file_tag_file_to_list($file_new,$type)); - - foreach($check_new_tags as $tag) { - if(! stristr($saved,$lbracket . file_tag_encode($tag) . $rbracket)) - $new_tags[] = $tag; - } - - $filetags_updated .= file_tag_list_to_file(implode(",",$new_tags),$type); - - // check for deleted tags to be removed from filetags in pconfig - $deleted_tags = array(); - $check_deleted_tags = explode(",",file_tag_file_to_list($file_old,$type)); - - foreach($check_deleted_tags as $tag) { - if(! stristr($file_new,$lbracket . file_tag_encode($tag) . $rbracket)) - $deleted_tags[] = $tag; - } - - foreach($deleted_tags as $key => $tag) { - $r = q("select file from item where uid = %d " . file_tag_file_query('item',$tag,$type), - intval($uid) - ); - - if(count($r)) { - unset($deleted_tags[$key]); - } - else { - $filetags_updated = str_replace($lbracket . file_tag_encode($tag) . $rbracket,'',$filetags_updated); - } - } - - if($saved != $filetags_updated) { - set_pconfig($uid,'system','filetags', $filetags_updated); - } - return true; - } - else - if(strlen($file_new)) { - set_pconfig($uid,'system','filetags', $file_new); - } - return true; -} - -function store_item_tag($uid,$iid,$otype,$type,$term,$url = '') { - if(! $term) - return false; - $r = q("select * from term - where uid = %d and oid = %d and otype = %d and type = %d - and term = '%s' and url = '%s' ", - intval($uid), - intval($iid), - intval($otype), - intval($type), - dbesc($term), - dbesc($url) - ); - if($r) - return false; - $r = q("insert into term (uid, oid, otype, type, term, url) - values( %d, %d, %d, %d, '%s', '%s') ", - intval($uid), - intval($iid), - intval($otype), - intval($type), - dbesc($term), - dbesc($url) - ); - return $r; -} - -function get_terms_oftype($arr,$type) { - $ret = array(); - if(! (is_array($arr) && count($arr))) - return $ret; - - if(! is_array($type)) - $type = array($type); - - foreach($type as $t) - foreach($arr as $x) - if($x['type'] == $t) - $ret[] = $x; - return $ret; -} - -function format_term_for_display($term) { - $s = ''; - if($term['type'] == TERM_HASHTAG) - $s .= '#'; - elseif($term['type'] == TERM_MENTION) - $s .= '@'; - - if($term['url']) $s .= '<a target="extlink" href="' . $term['url'] . '">' . htmlspecialchars($term['term']) . '</a>'; - else $s .= htmlspecialchars($term['term']); - return $s; -} + switch($item['resource_type']) { + case 'photo': + $post_type = t('photo'); + break; + case 'event': + $post_type = t('event'); + break; + default: + $post_type = t('status'); + if($item['mid'] != $item['parent_mid']) + $post_type = t('comment'); + break; + } -function file_tag_save_file($uid,$item,$file) { - $result = false; - if(! intval($uid)) - return false; + if(strlen($item['verb']) && (! activity_match($item['verb'],ACTIVITY_POST))) + $post_type = t('activity'); - $r = q("select file from item where id = %d and uid = %d limit 1", - intval($item), - intval($uid) - ); - if($r) { - if(! stristr($r[0]['file'],'[' . file_tag_encode($file) . ']')) - q("update item set file = '%s' where id = %d and uid = %d limit 1", - dbesc($r[0]['file'] . '[' . file_tag_encode($file) . ']'), - intval($item), - intval($uid) - ); - $saved = get_pconfig($uid,'system','filetags'); - if((! strlen($saved)) || (! stristr($saved,'[' . file_tag_encode($file) . ']'))) - set_pconfig($uid,'system','filetags',$saved . '[' . file_tag_encode($file) . ']'); - info( t('Item filed') ); - } - return true; + return $post_type; } -function file_tag_unsave_file($uid,$item,$file,$cat = false) { - $result = false; - if(! intval($uid)) - return false; - - if($cat == true) - $pattern = '<' . file_tag_encode($file) . '>' ; - else - $pattern = '[' . file_tag_encode($file) . ']' ; - - - $r = q("select file from item where id = %d and uid = %d limit 1", - intval($item), - intval($uid) - ); - if(! $r) - return false; - - q("update item set file = '%s' where id = %d and uid = %d limit 1", - dbesc(str_replace($pattern,'',$r[0]['file'])), - intval($item), - intval($uid) - ); - - $r = q("select file from item where uid = %d and deleted = 0 " . file_tag_file_query('item',$file,(($cat) ? 'category' : 'file')), - intval($uid) - ); - - if(! $r) { - $saved = get_pconfig($uid,'system','filetags'); - set_pconfig($uid,'system','filetags',str_replace($pattern,'',$saved)); - - } - return true; -} function normalise_openid($s) { return trim(str_replace(array('http://','https://'),array('',''),$s),'/'); @@ -1794,7 +1561,7 @@ function ids_to_querystr($arr,$idx = 'id') { // author_xchan and owner_xchan. If $abook is true also include the abook info. // This is needed in the API to save extra per item lookups there. -function xchan_query(&$items,$abook = false) { +function xchan_query(&$items,$abook = true) { $arr = array(); if($items && count($items)) { foreach($items as $item) { @@ -1806,8 +1573,10 @@ function xchan_query(&$items,$abook = false) { } if(count($arr)) { if($abook) { - $chans = q("select * from xchan left join hubloc on hubloc_hash = xchan_hash left join abook on abook_xchan = xchan_hash - where xchan_hash in (" . implode(',', $arr) . ") and ( hubloc_flags & " . intval(HUBLOC_FLAGS_PRIMARY) . " )"); + $chans = q("select * from xchan left join hubloc on hubloc_hash = xchan_hash left join abook on abook_xchan = xchan_hash and abook_channel = %d + where xchan_hash in (" . implode(',', $arr) . ") and ( hubloc_flags & " . intval(HUBLOC_FLAGS_PRIMARY) . " )", + intval($item['uid']) + ); } else { $chans = q("select xchan.*,hubloc.* from xchan left join hubloc on hubloc_hash = xchan_hash @@ -1936,67 +1705,3 @@ function jindent($json) { } -// Tag cloud functions - need to be adpated to this database format - - -function tagadelic($uid, $count = 0, $type = TERM_HASHTAG) { - - // Fetch tags - $r = q("select term, count(term) as total from term - where uid = %d and type = %d - and otype = %d - group by term order by total desc %s", - intval($uid), - intval($type), - intval(TERM_OBJ_POST), - ((intval($count)) ? "limit $count" : '') - ); - - if(! $r) - return array(); - - // Find minimum and maximum log-count. - $tags = array(); - $min = 1e9; - $max = -1e9; - - $x = 0; - foreach($r as $rr) { - $tags[$x][0] = $rr['term']; - $tags[$x][1] = log($rr['total']); - $tags[$x][2] = 0; - $min = min($min,$tags[$x][1]); - $max = max($max,$tags[$x][1]); - $x ++; - } - - usort($tags,'tags_sort'); - - $range = max(.01, $max - $min) * 1.0001; - - for($x = 0; $x < count($tags); $x ++) { - $tags[$x][2] = 1 + floor(5 * ($tags[$x][1] - $min) / $range); - } - - return $tags; -} - -function tags_sort($a,$b) { - if($a[0] == $b[0]) - return 0; - return((strtolower($a[0]) < strtolower($b[0])) ? -1 : 1); -} - - -function tagblock($link,$uid,$count = 0,$type = TERM_HASHTAG) { - $tab = 0; - $r = tagadelic($uid,$count,$type); - - if($r) { - echo '<div class="tags" align="center">'; - foreach($r as $rr) { - echo '<a href="'.$link .'/' . '?f=&tag=' . urlencode($rr[0]).'" class="tag'.$rr[2].'">'.$rr[0].'</a> '; - } - echo '</div>'; - } -} diff --git a/include/zot.php b/include/zot.php index 2eb3b5eb0..6c8a21d1a 100644 --- a/include/zot.php +++ b/include/zot.php @@ -874,8 +874,16 @@ function zot_import($arr) { $result = process_profile_delivery($i['notify']['sender'],$arr,$deliveries); } + elseif($i['message']['type'] === 'channel_sync') { +// $arr = get_channelsync_elements($i['message']); + $arr = $i['message']; + logger('Channel sync received: ' . print_r($arr,true), LOGGER_DATA); + logger('Channel sync recipients: ' . print_r($deliveries,true), LOGGER_DATA); + +// $result = process_channelsync_delivery($i['notify']['sender'],$arr,$deliveries); + } } if($result) $return = array_merge($return,$result); @@ -1017,15 +1025,21 @@ function process_delivery($sender,$arr,$deliveries,$relay) { $channel = $r[0]; + $tag_delivery = tgroup_check($channel['channel_id'],$arr); + $perm = (($arr['mid'] == $arr['parent_mid']) ? 'send_stream' : 'post_comments'); - if(! perm_is_allowed($channel['channel_id'],$sender['hash'],$perm)) { + if((! perm_is_allowed($channel['channel_id'],$sender['hash'],$perm)) && (! $tag_delivery)) { logger("permission denied for delivery {$channel['channel_id']}"); $result[] = array($d['hash'],'permission denied'); continue; } if($arr['item_restrict'] & ITEM_DELETED) { + + // remove_community_tag is a no-op if this isn't a community tag activity + remove_community_tag($sender,$arr,$channel['channel_id']); + $item_id = delete_imported_item($sender,$arr,$channel['channel_id']); $result[] = array($d['hash'],'deleted'); @@ -1038,7 +1052,7 @@ function process_delivery($sender,$arr,$deliveries,$relay) { continue; } - // for events, extract the event info and create and event linked to an item + // for events, extract the event info and create an event linked to an item if((x($arr,'obj_type')) && (activity_match($arr['obj_type'],ACTIVITY_OBJ_EVENT))) { require_once('include/event.php'); @@ -1106,6 +1120,68 @@ function process_delivery($sender,$arr,$deliveries,$relay) { } +function remove_community_tag($sender,$arr,$uid) { + + if(! (activity_match($arr['verb'],ACTIVITY_TAG) && ($arr['obj_type'] == ACTIVITY_OBJ_TAGTERM))) + return; + + logger('remove_community_tag: invoked'); + + + if(! get_pconfig($uid,'system','blocktags')) { + logger('remove_community tag: permission denied.'); + return; + } + + $r = q("select * from item where mid = '%s' and uid = %d limit 1", + dbesc($arr['mid']), + intval($uid) + ); + if(! $r) { + logger('remove_community_tag: no item'); + return; + } + + if(($sender['hash'] != $r[0]['owner_xchan']) && ($sender['hash'] != $r[0]['author_xchan'])) { + logger('remove_community_tag: sender not authorised.'); + return; + } + + $i = $r[0]; + + if($i['target']) + $i['target'] = json_decode($i['target'],true); + if($i['object']) + $i['object'] = json_decode($i['object'],true); + + if(! ($i['target'] && $i['object'])) { + logger('remove_community_tag: no target/object'); + return; + } + + $message_id = $i['target']['id']; + + $r = q("select id from item where mid = '%s' and uid = %d limit 1", + dbesc($message_id), + intval($uid) + ); + if(! $r) { + logger('remove_community_tag: no parent message'); + return; + } + + $x = q("delete from term where uid = %d and oid = %d and otype = %d and type = %d and term = '%s' and url = '%s' limit 1", + intval($uid), + intval($r[0]['id']), + intval(TERM_OBJ_POST), + intval(TERM_HASHTAG), + dbesc($i['object']['title']), + dbesc(get_rel_link($i['object']['link'],'alternate')) + ); + + return; +} + function update_imported_item($sender,$item,$uid) { item_store_update($item); @@ -1215,6 +1291,7 @@ function import_directory_profile($hash,$profile) { $arr['xprof_hash'] = $hash; $arr['xprof_desc'] = (($profile['description']) ? htmlentities($profile['description'], ENT_COMPAT,'UTF-8',false) : ''); $arr['xprof_dob'] = datetime_convert('','',$profile['birthday'],'Y-m-d'); // !!!! check this for 0000 year + $arr['xprof_age'] = (($profile['age']) ? intval($profile['age']) : 0); $arr['xprof_gender'] = (($profile['gender']) ? htmlentities($profile['gender'], ENT_COMPAT,'UTF-8',false) : ''); $arr['xprof_marital'] = (($profile['marital']) ? htmlentities($profile['marital'], ENT_COMPAT,'UTF-8',false) : ''); $arr['xprof_sexual'] = (($profile['sexual']) ? htmlentities($profile['sexual'], ENT_COMPAT,'UTF-8',false) : ''); @@ -1235,7 +1312,6 @@ function import_directory_profile($hash,$profile) { $arr['xprof_keywords'] = implode(' ',$clean); - $r = q("select * from xprof where xprof_hash = '%s' limit 1", dbesc($hash) ); @@ -1251,6 +1327,7 @@ function import_directory_profile($hash,$profile) { $x = q("update xprof set xprof_desc = '%s', xprof_dob = '%s', + xprof_age = %d, xprof_gender = '%s', xprof_marital = '%s', xprof_sexual = '%s', @@ -1262,6 +1339,7 @@ function import_directory_profile($hash,$profile) { where xprof_hash = '%s' limit 1", dbesc($arr['xprof_desc']), dbesc($arr['xprof_dob']), + intval($arr['xprof_age']), dbesc($arr['xprof_gender']), dbesc($arr['xprof_marital']), dbesc($arr['xprof_sexual']), @@ -1276,10 +1354,11 @@ function import_directory_profile($hash,$profile) { } else { $update = true; - $x = q("insert into xprof (xprof_hash, xprof_desc, xprof_dob, xprof_gender, xprof_marital, xprof_sexual, xprof_locale, xprof_region, xprof_postcode, xprof_country, xprof_keywords) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ", + $x = q("insert into xprof (xprof_hash, xprof_desc, xprof_dob, xprof_age, xprof_gender, xprof_marital, xprof_sexual, xprof_locale, xprof_region, xprof_postcode, xprof_country, xprof_keywords) values ('%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ", dbesc($arr['xprof_hash']), dbesc($arr['xprof_desc']), dbesc($arr['xprof_dob']), + intval($arr['xprof_age']), dbesc($arr['xprof_gender']), dbesc($arr['xprof_marital']), dbesc($arr['xprof_sexual']), |