diff options
Diffstat (limited to 'include')
62 files changed, 4698 insertions, 4941 deletions
diff --git a/include/AccessList.php b/include/AccessList.php new file mode 100644 index 000000000..43f1de111 --- /dev/null +++ b/include/AccessList.php @@ -0,0 +1,148 @@ +<?php + + +class AccessList { + + private $allow_cid; + private $allow_gid; + private $deny_cid; + private $deny_gid; + + /* indicates if we are using the default constructor values or values that have been set explicitly. */ + + private $explicit; + + function __construct($channel) { + + if($channel) { + $this->allow_cid = $channel['channel_allow_cid']; + $this->allow_gid = $channel['channel_allow_gid']; + $this->deny_cid = $channel['channel_deny_cid']; + $this->deny_gid = $channel['channel_deny_gid']; + } + else { + $this->allow_cid = ''; + $this->allow_gid = ''; + $this->deny_cid = ''; + $this->deny_gid = ''; + } + + $this->explicit = false; + } + + function get_explicit() { + return $this->explicit; + } + + /** + * Set AccessList from strings such as those in already + * existing stored data items + */ + + function set($arr,$explicit = true) { + $this->allow_cid = $arr['allow_cid']; + $this->allow_gid = $arr['allow_gid']; + $this->deny_cid = $arr['deny_cid']; + $this->deny_gid = $arr['deny_gid']; + + $this->explicit = $explicit; + } + + /** + * return an array consisting of the current + * access list components where the elements + * are directly storable. + */ + + function get() { + return array( + 'allow_cid' => $this->allow_cid, + 'allow_gid' => $this->allow_gid, + 'deny_cid' => $this->deny_cid, + 'deny_gid' => $this->deny_gid, + ); + } + + /** + * Set AccessList from arrays, such as those provided by + * acl_selector(). For convenience, a string (or non-array) input is + * assumed to be a comma-separated list and auto-converted into an array. + */ + + function set_from_array($arr,$explicit = true) { + $this->allow_cid = perms2str((is_array($arr['contact_allow'])) + ? $arr['contact_allow'] : explode(',',$arr['contact_allow'])); + $this->allow_gid = perms2str((is_array($arr['group_allow'])) + ? $arr['group_allow'] : explode(',',$arr['group_allow'])); + $this->deny_cid = perms2str((is_array($arr['contact_deny'])) + ? $arr['contact_deny'] : explode(',',$arr['contact_deny'])); + $this->deny_gid = perms2str((is_array($arr['group_deny'])) + ? $arr['group_deny'] : explode(',',$arr['group_deny'])); + + $this->explicit = $explicit; + } + + function is_private() { + return (($this->allow_cid || $this->allow_gid || $this->deny_cid || $this->deny_gid) ? true : false); + } + +} + +/** + * @brief Used to wrap ACL elements in angle brackets for storage. + * + * @param[in,out] array &$item + */ +function sanitise_acl(&$item) { + if (strlen($item)) + $item = '<' . notags(trim($item)) . '>'; + else + unset($item); +} + +/** + * @brief Convert an ACL array to a storable string. + * + * @param array $p + * @return array + */ +function perms2str($p) { + $ret = ''; + + if (is_array($p)) + $tmp = $p; + else + $tmp = explode(',', $p); + + if (is_array($tmp)) { + array_walk($tmp, 'sanitise_acl'); + $ret = implode('', $tmp); + } + + return $ret; +} + + +/** + * @brief Turn user/group ACLs stored as angle bracketed text into arrays. + * + * turn string array of angle-bracketed elements into string array + * e.g. "<123xyz><246qyo><sxo33e>" => array(123xyz,246qyo,sxo33e); + * + * @param string $s + * @return array + */ +function expand_acl($s) { + $ret = array(); + + if(strlen($s)) { + $t = str_replace('<','',$s); + $a = explode('>',$t); + foreach($a as $aa) { + if($aa) + $ret[] = $aa; + } + } + + return $ret; +} diff --git a/include/Contact.php b/include/Contact.php index a27a8eca9..008574d8f 100644 --- a/include/Contact.php +++ b/include/Contact.php @@ -22,9 +22,8 @@ function rconnect_url($channel_id,$xchan) { if(($r) && ($r[0]['xchan_follow'])) return $r[0]['xchan_follow']; - $r = q("select hubloc_url from hubloc where hubloc_hash = '%s' and ( hubloc_flags & %d )>0 limit 1", - dbesc($xchan), - intval(HUBLOC_FLAGS_PRIMARY) + $r = q("select hubloc_url from hubloc where hubloc_hash = '%s' and hubloc_primary = 1 limit 1", + dbesc($xchan) ); if($r) @@ -35,42 +34,37 @@ function rconnect_url($channel_id,$xchan) { function abook_connections($channel_id, $sql_conditions = '') { $r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d - and not ( abook_flags & %d )>0 $sql_conditions", - intval($channel_id), - intval(ABOOK_FLAG_SELF) + and abook_self = 0 $sql_conditions", + intval($channel_id) ); return(($r) ? $r : array()); } function abook_self($channel_id) { $r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d - and ( abook_flags & %d )>0 limit 1", - intval($channel_id), - intval(ABOOK_FLAG_SELF) + and abook_self = 1 limit 1", + intval($channel_id) ); return(($r) ? $r[0] : array()); } function channelx_by_nick($nick) { - $r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_address = '%s' and not ( channel_pageflags & %d )>0 LIMIT 1", - dbesc($nick), - intval(PAGE_REMOVED) + $r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_address = '%s' and channel_removed = 0 LIMIT 1", + dbesc($nick) ); return(($r) ? $r[0] : false); } function channelx_by_hash($hash) { - $r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_hash = '%s' and not ( channel_pageflags & %d )>0 LIMIT 1", - dbesc($hash), - intval(PAGE_REMOVED) + $r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_hash = '%s' and channel_removed = 0 LIMIT 1", + dbesc($hash) ); return(($r) ? $r[0] : false); } function channelx_by_n($id) { - $r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_id = %d and not ( channel_pageflags & %d )>0 LIMIT 1", - dbesc($id), - intval(PAGE_REMOVED) + $r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_id = %d and channel_removed = 0 LIMIT 1", + dbesc($id) ); return(($r) ? $r[0] : false); } @@ -129,9 +123,40 @@ function vcard_from_xchan($xchan, $observer = null, $mode = '') { function abook_toggle_flag($abook,$flag) { - $r = q("UPDATE abook set abook_flags = (abook_flags %s %d) where abook_id = %d and abook_channel = %d", - db_getfunc('^'), - intval($flag), + $field = ''; + + switch($flag) { + case ABOOK_FLAG_BLOCKED: + $field = 'abook_blocked'; + break; + case ABOOK_FLAG_IGNORED: + $field = 'abook_ignored'; + break; + case ABOOK_FLAG_HIDDEN: + $field = 'abook_hidden'; + break; + case ABOOK_FLAG_ARCHIVED: + $field = 'abook_archived'; + break; + case ABOOK_FLAG_PENDING: + $field = 'abook_pending'; + break; + case ABOOK_FLAG_UNCONNECTED: + $field = 'abook_unconnected'; + break; + case ABOOK_FLAG_SELF: + $field = 'abook_self'; + break; + case ABOOK_FLAG_FEED: + $field = 'abook_feed'; + break; + default: + break; + } + if(! $field) + return; + + $r = q("UPDATE abook set $field = (1 - $field) where abook_id = %d and abook_channel = %d", intval($abook['abook_id']), intval($abook['abook_channel']) ); @@ -139,7 +164,7 @@ function abook_toggle_flag($abook,$flag) { // if unsetting the archive bit, update the timestamps so we'll try to connect for an additional 30 days. - if(($flag === ABOOK_FLAG_ARCHIVED) && ($abook['abook_flags'] & ABOOK_FLAG_ARCHIVED)) { + if(($flag === ABOOK_FLAG_ARCHIVED) && (intval($abook['abook_archived']))) { $r = q("update abook set abook_connected = '%s', abook_updated = '%s' where abook_id = %d and abook_channel = %d", dbesc(datetime_convert()), @@ -258,25 +283,22 @@ function channel_remove($channel_id, $local = true, $unset_session=true) { if(! $local) { - $r = q("update channel set channel_deleted = '%s', channel_pageflags = (channel_pageflags | %d), channel_r_stream = 0, channel_r_profile = 0, + $r = q("update channel set channel_deleted = '%s', channel_removed = 1, 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", dbesc(datetime_convert()), - intval(PAGE_REMOVED), intval($channel_id) ); - $r = q("update hubloc set hubloc_flags = (hubloc_flags | %d) where hubloc_hash = '%s'", - intval(HUBLOC_FLAGS_DELETED), + $r = q("update hubloc set hubloc_deleted = 1 where hubloc_hash = '%s'", dbesc($channel['channel_hash']) ); - $r = q("update xchan set xchan_flags = (xchan_flags | %d) where xchan_hash = '%s'", - intval(XCHAN_FLAGS_DELETED), + $r = q("update xchan set xchan_deleted = 1 where xchan_hash = '%s'", dbesc($channel['channel_hash']) ); @@ -298,19 +320,17 @@ function channel_remove($channel_id, $local = true, $unset_session=true) { q("DELETE FROM `spam` WHERE `uid` = %d", intval($channel_id)); - q("delete from abook where abook_xchan = '%s' and (abook_flags & %d)>0", - dbesc($channel['channel_hash']), - dbesc(ABOOK_FLAG_SELF) + q("delete from abook where abook_xchan = '%s' and abook_self = 1 ", + dbesc($channel['channel_hash']) ); - $r = q("update channel set channel_deleted = '%s', channel_pageflags = (channel_pageflags | %d) where channel_id = %d", + $r = q("update channel set channel_deleted = '%s', channel_removed = 1 where channel_id = %d", dbesc(datetime_convert()), - intval(PAGE_REMOVED), intval($channel_id) ); // if this was the default channel, set another one as default if($a->account['account_default_channel'] == $channel_id) { - $r = q("select channel_id from channel where channel_account_id = %d and not ( channel_pageflags & %d)>0 limit 1", + $r = q("select channel_id from channel where channel_account_id = %d and channel_removed = 0 limit 1", intval($a->account['account_id']), intval(PAGE_REMOVED)); if ($r) { @@ -327,8 +347,7 @@ function channel_remove($channel_id, $local = true, $unset_session=true) { } - $r = q("update hubloc set hubloc_flags = (hubloc_flags | %d) where hubloc_hash = '%s' and hubloc_url = '%s' ", - intval(HUBLOC_FLAGS_DELETED), + $r = q("update hubloc set hubloc_deleted = 1 where hubloc_hash = '%s' and hubloc_url = '%s' ", dbesc($channel['channel_hash']), dbesc(z_root()) ); @@ -337,16 +356,14 @@ function channel_remove($channel_id, $local = true, $unset_session=true) { $hublocs = 0; - $r = q("select hubloc_id from hubloc where hubloc_hash = '%s' and not (hubloc_flags & %d)>0", - dbesc($channel['channel_hash']), - intval(HUBLOC_FLAGS_DELETED) + $r = q("select hubloc_id from hubloc where hubloc_hash = '%s' and hubloc_deleted = 0", + dbesc($channel['channel_hash']) ); if($r) $hublocs = count($r); if(! $hublocs) { - $r = q("update xchan set xchan_flags = (xchan_flags | %d) where xchan_hash = '%s' ", - intval(XCHAN_FLAGS_DELETED), + $r = q("update xchan set xchan_deleted = 1 where xchan_hash = '%s' ", dbesc($channel['channel_hash']) ); } @@ -389,10 +406,8 @@ function mark_orphan_hubsxchans() { if($dirmode == DIRECTORY_MODE_NORMAL) return; - $r = q("update hubloc set hubloc_status = (hubloc_status | %d) where (hubloc_status & %d) = 0 + $r = q("update hubloc set hubloc_error = 1 where hubloc_error = 0 and hubloc_network = 'zot' and hubloc_connected < %s - interval %s", - intval(HUBLOC_OFFLINE), - intval(HUBLOC_OFFLINE), db_utcnow(), db_quoteinterval('36 day') ); @@ -409,27 +424,21 @@ function mark_orphan_hubsxchans() { // } - $r = q("select hubloc_id, hubloc_hash from hubloc where (hubloc_status & %d)>0 and not (hubloc_flags & %d)>0", - intval(HUBLOC_OFFLINE), - intval(HUBLOC_FLAGS_ORPHANCHECK) - ); + $r = q("select hubloc_id, hubloc_hash from hubloc where hubloc_error = 0 and hubloc_orphancheck = 0"); if($r) { foreach($r as $rr) { // see if any other hublocs are still alive for this channel - $x = q("select * from hubloc where hubloc_hash = '%s' and not (hubloc_status & %d)>0", - dbesc($rr['hubloc_hash']), - intval(HUBLOC_OFFLINE) + $x = q("select * from hubloc where hubloc_hash = '%s' and hubloc_error = 0", + dbesc($rr['hubloc_hash']) ); if($x) { // yes - if the xchan was marked as an orphan, undo it - $y = q("update xchan set xchan_flags = (xchan_flags & ~%d) where (xchan_flags & %d)>0 and xchan_hash = '%s'", - intval(XCHAN_FLAGS_ORPHAN), - intval(XCHAN_FLAGS_ORPHAN), + $y = q("update xchan set xchan_orphan = 0 where xchan_orphan = 1 and xchan_hash = '%s'", dbesc($rr['hubloc_hash']) ); @@ -438,16 +447,14 @@ function mark_orphan_hubsxchans() { // nope - mark the xchan as an orphan - $y = q("update xchan set xchan_flags = (xchan_flags | %d) where xchan_hash = '%s'", - intval(XCHAN_FLAGS_ORPHAN), + $y = q("update xchan set xchan_orphan = 1 where xchan_hash = '%s'", dbesc($rr['hubloc_hash']) ); } // mark that we've checked this entry so we don't need to do it again - $y = q("update hubloc set hubloc_flags = (hubloc_flags | %d) where hubloc_id = %d", - intval(HUBLOC_FLAGS_ORPHANCHECK), + $y = q("update hubloc set hubloc_orphancheck = 1 where hubloc_id = %d", dbesc($rr['hubloc_id']) ); } @@ -516,13 +523,11 @@ function remove_all_xchan_resources($xchan, $channel_id = 0) { // directory servers need to keep the record around for sync purposes - mark it deleted - $r = q("update hubloc set hubloc_flags = (hubloc_flags | %d) where hubloc_hash = '%s'", - intval(HUBLOC_FLAGS_DELETED), + $r = q("update hubloc set hubloc_deleted = 1 where hubloc_hash = '%s'", dbesc($xchan) ); - $r = q("update xchan set xchan_flags = (xchan_flags | %d) where xchan_hash = '%s'", - intval(XCHAN_FLAGS_DELETED), + $r = q("update xchan set xchan_deleted = 1 where xchan_hash = '%s'", dbesc($xchan) ); } @@ -539,8 +544,7 @@ function contact_remove($channel_id, $abook_id) { $archive = get_pconfig($channel_id, 'system','archive_removed_contacts'); if($archive) { - q("update abook set abook_flags = ( abook_flags | %d ) where abook_id = %d and abook_channel = %d", - intval(ABOOK_FLAG_ARCHIVED), + q("update abook set abook_archived = 1 where abook_id = %d and abook_channel = %d", intval($abook_id), intval($channel_id) ); @@ -557,7 +561,7 @@ function contact_remove($channel_id, $abook_id) { $abook = $r[0]; - if($abook['abook_flags'] & ABOOK_FLAG_SELF) + if(intval($abook['abook_self'])) return false; diff --git a/include/ConversationObject.php b/include/ConversationObject.php index af0bb8d2c..7e0d67c10 100644 --- a/include/ConversationObject.php +++ b/include/ConversationObject.php @@ -166,11 +166,11 @@ class Conversation extends BaseObject { if(($item->get_data_value('author_xchan') === $ob_hash) || ($item->get_data_value('owner_xchan') === $ob_hash)) $item->set_commentable(true); - if($item->get_data_value('item_flags') & ITEM_NOCOMMENT) { + if(intval($item->get_data_value('item_nocomment'))) { $item->set_commentable(false); } elseif(($this->observer) && (! $item->is_commentable())) { - if((array_key_exists('owner',$item->data)) && ($item->data['owner']['abook_flags'] & ABOOK_FLAG_SELF)) + if((array_key_exists('owner',$item->data)) && intval($item->data['owner']['abook_self'])) $item->set_commentable(perm_is_allowed($this->profile_owner,$this->observer['xchan_hash'],'post_comments')); else $item->set_commentable(can_comment_on_post($this->observer['xchan_hash'],$item->data)); diff --git a/include/Import/Importer.php b/include/Import/Importer.php index 5e684cd8e..cddfac7b5 100644 --- a/include/Import/Importer.php +++ b/include/Import/Importer.php @@ -1,11 +1,11 @@ <?php /** @file */ -namespace RedMatrix\Import; +namespace Hubzilla\Import; /** * @brief Class Import * - * @package RedMatrix\Import + * @package Hubzilla\Import */ class Import { diff --git a/include/Import/import_diaspora.php b/include/Import/import_diaspora.php index fca9fa4f2..a0f473b50 100644 --- a/include/Import/import_diaspora.php +++ b/include/Import/import_diaspora.php @@ -57,6 +57,10 @@ function import_diaspora($data) { $channel_id = $c['channel']['channel_id']; + // Hubzilla only: Turn on the Diaspora protocol so that follow requests will be sent. + + set_pconfig($channel_id,'system','diaspora_allowed','1'); + // todo - add auto follow settings, (and strip exif in hubzilla) $location = escape_tags($data['user']['profile']['location']); @@ -70,7 +74,6 @@ function import_diaspora($data) { ); if($data['user']['profile']['nsfw']) { - // fixme for hubzilla which doesn't use pageflags any more q("update channel set channel_pageflags = (channel_pageflags | %d) where channel_id = %d", intval(PAGE_ADULT), intval($channel_id) diff --git a/include/Import/refimport.php b/include/Import/refimport.php index b9b6bf639..3ef8870ac 100644 --- a/include/Import/refimport.php +++ b/include/Import/refimport.php @@ -88,7 +88,11 @@ function refimport_content(&$a) { $arr['author_xchan'] = $channel['channel_hash']; $arr['owner_xchan'] = $channel['channel_hash']; $arr['app'] = REFLECT_BLOGNAME; - $arr['item_flags'] = ITEM_ORIGIN|ITEM_WALL|ITEM_THREAD_TOP; + + $arr['item_origin'] = 1; + $arr['item_wall'] = 1; + $arr['item_thread_top'] = 1; + $arr['verb'] = ACTIVITY_POST; // this is an assumption @@ -205,7 +209,7 @@ function reflect_find_user($users,$name) { function reflect_comment_store($channel,$post,$comment,$user) { - // if the commenter was the channel owner, use their redmatrix xchan + // if the commenter was the channel owner, use their hubzilla xchan if($comment['author'] === REFLECT_EXPORTUSERNAME && $comment['registered']) $hash = $channel['xchan_hash']; @@ -256,7 +260,8 @@ function reflect_comment_store($channel,$post,$comment,$user) { $arr['edited'] = $comment['created']; $arr['author_xchan'] = $hash; $arr['owner_xchan'] = $channel['channel_hash']; - $arr['item_flags'] = ITEM_ORIGIN|ITEM_WALL; + $arr['item_origin'] = 1; + $arr['item_wall'] = 1; $arr['verb'] = ACTIVITY_POST; $arr['comment_policy'] = 'contacts'; diff --git a/include/ItemObject.php b/include/ItemObject.php index d5601edf5..5296a1cf0 100644 --- a/include/ItemObject.php +++ b/include/ItemObject.php @@ -152,7 +152,7 @@ class Item extends BaseObject { } } - $consensus = (($item['item_flags'] & ITEM_CONSENSUS) ? true : false); + $consensus = (intval($item['item_consensus']) ? true : false); if($consensus) { $response_verbs[] = 'agree'; $response_verbs[] = 'disagree'; @@ -212,9 +212,9 @@ class Item extends BaseObject { 'do' => t("Add Star"), 'undo' => t("Remove Star"), 'toggle' => t("Toggle Star Status"), - 'classdo' => (($item['item_flags'] & ITEM_STARRED) ? "hidden" : ""), - 'classundo' => (($item['item_flags'] & ITEM_STARRED) ? "" : "hidden"), - 'isstarred' => (($item['item_flags'] & ITEM_STARRED) ? "starred icon-star" : "unstarred icon-star-empty"), + 'classdo' => (intval($item['item_starred']) ? "hidden" : ""), + 'classundo' => (intval($item['item_starred']) ? "" : "hidden"), + 'isstarred' => (intval($item['item_starred']) ? "starred icon-star" : "unstarred icon-star-empty"), 'starred' => t('starred'), ); @@ -224,9 +224,9 @@ class Item extends BaseObject { } - $verified = (($item['item_flags'] & ITEM_VERIFIED) ? t('Message signature validated') : ''); - $forged = ((($item['sig']) && (! ($item['item_flags'] & ITEM_VERIFIED))) ? t('Message signature incorrect') : ''); - $unverified = '' ; // (($this->is_wall_to_wall() && (! ($item['item_flags'] & ITEM_VERIFIED))) ? t('Message cannot be verified') : ''); + $verified = (intval($item['item_verified']) ? t('Message signature validated') : ''); + $forged = ((($item['sig']) && (! intval($item['item_verified']))) ? t('Message signature incorrect') : ''); + $unverified = '' ; // (($this->is_wall_to_wall() && (! intval($item['item_verified']))) ? t('Message cannot be verified') : ''); @@ -286,6 +286,7 @@ class Item extends BaseObject { 'body' => $body, 'text' => strip_tags($body), 'id' => $this->get_id(), + 'mid' => $item['mid'], 'isevent' => $isevent, 'attend' => $attend, 'consensus' => $consensus, @@ -301,6 +302,7 @@ class Item extends BaseObject { 'vwall' => t('via Wall-To-Wall:'), 'profile_url' => $profile_link, 'item_photo_menu' => item_photo_menu($item), + 'dreport' => t('Delivery Report'), 'name' => $profile_name, 'thumb' => $profile_avatar, 'osparkle' => $osparkle, @@ -373,12 +375,16 @@ class Item extends BaseObject { $result['children'] = array(); $nb_children = count($children); + $visible_comments = get_config('system','expanded_comments'); + if($visible_comments === false) + $visible_comments = 3; + if(($this->get_display_mode() === 'normal') && ($nb_children > 0)) { foreach($children as $child) { $result['children'][] = $child->get_template_data($conv_responses, $thread_level + 1); } // Collapse - if(($nb_children > 2) || ($thread_level > 1)) { + if(($nb_children > $visible_comments) || ($thread_level > 1)) { $result['children'][0]['comment_firstcollapsed'] = true; $result['children'][0]['num_comments'] = $comment_count_txt; $result['children'][0]['hide_text'] = t('[+] show all'); @@ -386,7 +392,7 @@ class Item extends BaseObject { $result['children'][$nb_children - 1]['comment_lastcollapsed'] = true; } else { - $result['children'][$nb_children - 3]['comment_lastcollapsed'] = true; + $result['children'][$nb_children - ($visible_comments + 1)]['comment_lastcollapsed'] = true; } } } diff --git a/include/RedDAV/RedDirectory.php b/include/RedDAV/RedDirectory.php index 922be378d..507fde46f 100644 --- a/include/RedDAV/RedDirectory.php +++ b/include/RedDAV/RedDirectory.php @@ -50,7 +50,7 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { */ public function __construct($ext_path, &$auth_plugin) { // $ext_path = urldecode($ext_path); - //logger('directory ' . $ext_path, LOGGER_DATA); + logger('directory ' . $ext_path, LOGGER_DATA); $this->ext_path = $ext_path; // remove "/cloud" from the beginning of the path $modulename = get_app()->module; @@ -80,7 +80,7 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { * @return array \Sabre\DAV\INode[] */ public function getChildren() { - //logger('children for ' . $this->ext_path, LOGGER_DATA); + logger('children for ' . $this->ext_path, LOGGER_DATA); $this->log(); if (get_config('system', 'block_public') && (! $this->auth->channel_id) && (! $this->auth->observer)) { @@ -200,9 +200,8 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { $mimetype = z_mime_content_type($name); - $c = q("SELECT * FROM channel WHERE channel_id = %d AND NOT (channel_pageflags & %d)>0 LIMIT 1", - intval($this->auth->owner_id), - intval(PAGE_REMOVED) + $c = q("SELECT * FROM channel WHERE channel_id = %d AND channel_removed = 0 LIMIT 1", + intval($this->auth->owner_id) ); if (! $c) { @@ -213,28 +212,55 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { $filesize = 0; $hash = random_string(); - $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, folder, flags, filetype, filesize, revision, data, created, edited, allow_cid, allow_gid, deny_cid, deny_gid ) - VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", + $f = 'store/' . $this->auth->owner_nick . '/' . (($this->os_path) ? $this->os_path . '/' : '') . $hash; + + $direct = null; + + if($this->folder_hash) { + $r = q("select * from attach where hash = '%s' and is_dir = 1 and uid = %d limit 1", + dbesc($this->folder_hash), + intval($c[0]['channel_id']) + ); + if($r) + $direct = $r[0]; + } + + if(($direct) && (($direct['allow_cid']) || ($direct['allow_gid']) || ($direct['deny_cid']) || ($direct['deny_gid']))) { + $allow_cid = $direct['allow_cid']; + $allow_gid = $direct['allow_gid']; + $deny_cid = $direct['deny_cid']; + $deny_gid = $direct['deny_gid']; + } + else { + $allow_cid = $c[0]['channel_allow_cid']; + $allow_gid = $c[0]['channel_allow_gid']; + $deny_cid = $c[0]['channel_deny_cid']; + $deny_gid = $c[0]['channel_deny_gid']; + } + + $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, folder, os_storage, filetype, filesize, revision, is_photo, data, created, edited, allow_cid, allow_gid, deny_cid, deny_gid ) + VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", intval($c[0]['channel_account_id']), intval($c[0]['channel_id']), dbesc($hash), dbesc($this->auth->observer), dbesc($name), dbesc($this->folder_hash), - dbesc(ATTACH_FLAG_OS), + intval(1), dbesc($mimetype), intval($filesize), intval(0), + intval($is_photo), dbesc($this->os_path . '/' . $hash), dbesc(datetime_convert()), dbesc(datetime_convert()), - dbesc($c[0]['channel_allow_cid']), - dbesc($c[0]['channel_allow_gid']), - dbesc($c[0]['channel_deny_cid']), - dbesc($c[0]['channel_deny_gid']) + dbesc($allow_cid), + dbesc($allow_gid), + dbesc($deny_cid), + dbesc($deny_gid) ); - $f = 'store/' . $this->auth->owner_nick . '/' . (($this->os_path) ? $this->os_path . '/' : '') . $hash; + // returns the number of bytes that were written to the file, or FALSE on failure $size = file_put_contents($f, $data); @@ -248,9 +274,20 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { // returns now $edited = datetime_convert(); + + + $is_photo = 0; + $x = @getimagesize($f); + logger('getimagesize: ' . print_r($x,true), LOGGER_DATA); + if(($x) && ($x[2] === IMAGETYPE_GIF || $x[2] === IMAGETYPE_JPEG || $x[2] === IMAGETYPE_PNG)) { + $is_photo = 1; + } + + // updates entry with filesize and timestamp - $d = q("UPDATE attach SET filesize = '%s', edited = '%s' WHERE hash = '%s' AND uid = %d", + $d = q("UPDATE attach SET filesize = '%s', is_photo = %d, edited = '%s' WHERE hash = '%s' AND uid = %d", dbesc($size), + intval($is_photo), dbesc($edited), dbesc($hash), intval($c[0]['channel_id']) @@ -281,6 +318,23 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { return; } } + + if($is_photo) { + $album = ''; + if($this->folder_hash) { + $f1 = q("select filename from attach WHERE hash = '%s' AND uid = %d", + dbesc($this->folder_hash), + intval($c[0]['channel_id']) + ); + if($f1) + $album = $f1[0]['filename']; + } + + require_once('include/photos.php'); + $args = array( 'resource_id' => $hash, 'album' => $album, 'os_path' => $f, 'filename' => $name, 'getimagesize' => $x, 'directory' => $direct); + $p = photo_upload($c[0],get_app()->get_observer(),$args); + } + } /** @@ -296,9 +350,8 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { throw new DAV\Exception\Forbidden('Permission denied.'); } - $r = q("SELECT * FROM channel WHERE channel_id = %d AND NOT (channel_pageflags & %d)>0 LIMIT 1", - intval($this->auth->owner_id), - intval(PAGE_REMOVED) + $r = q("SELECT * FROM channel WHERE channel_id = %d AND channel_removed = 0 LIMIT 1", + intval($this->auth->owner_id) ); if ($r) { @@ -340,15 +393,14 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { * @return void */ function getDir() { - //logger($this->ext_path, LOGGER_DEBUG); + + logger('GetDir: ' . $this->ext_path, LOGGER_DEBUG); $this->auth->log(); $modulename = get_app()->module; $file = $this->ext_path; $x = strpos($file, '/' . $modulename); - if ($x === false) - return; if ($x === 0) { $file = substr($file, strlen($modulename) + 1); } @@ -367,9 +419,8 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { $channel_name = $path_arr[0]; - $r = q("SELECT channel_id FROM channel WHERE channel_address = '%s' AND NOT ( channel_pageflags & %d )>0 LIMIT 1", - dbesc($channel_name), - intval(PAGE_REMOVED) + $r = q("SELECT channel_id FROM channel WHERE channel_address = '%s' AND channel_removed = 0 LIMIT 1", + dbesc($channel_name) ); if (! $r) { @@ -385,14 +436,12 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { $os_path = ''; for ($x = 1; $x < count($path_arr); $x++) { - $r = q("select id, hash, filename, flags from attach where folder = '%s' and filename = '%s' and uid = %d and (flags & %d)>0", + $r = q("select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0", dbesc($folder), dbesc($path_arr[$x]), - intval($channel_id), - intval(ATTACH_FLAG_DIR) + intval($channel_id) ); - - if ($r && ( $r[0]['flags'] & ATTACH_FLAG_DIR)) { + if ($r && intval($r[0]['is_dir'])) { $folder = $r[0]['hash']; if (strlen($os_path)) $os_path .= '/'; @@ -445,9 +494,8 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { $free = disk_free_space('store'); if ($this->auth->owner_id) { - $c = q("select * from channel where channel_id = %d and not (channel_pageflags & %d)>0 limit 1", - intval($this->auth->owner_id), - intval(PAGE_REMOVED) + $c = q("select * from channel where channel_id = %d and channel_removed = 0 limit 1", + intval($this->auth->owner_id) ); $ulimit = service_class_fetch($c[0]['channel_id'], 'attach_upload_limit'); diff --git a/include/RedDAV/RedFile.php b/include/RedDAV/RedFile.php index b7aa5473a..ec6871a69 100644 --- a/include/RedDAV/RedFile.php +++ b/include/RedDAV/RedFile.php @@ -49,7 +49,7 @@ class RedFile extends DAV\Node implements DAV\IFile { $this->data = $data; $this->auth = $auth; - //logger(print_r($this->data, true), LOGGER_DATA); + logger(print_r($this->data, true), LOGGER_DATA); } /** @@ -97,24 +97,49 @@ class RedFile extends DAV\Node implements DAV\IFile { $size = 0; // @todo only 3 values are needed - $c = q("SELECT * FROM channel WHERE channel_id = %d AND (channel_pageflags & %d) = 0 LIMIT 1", - intval($this->auth->owner_id), - intval(PAGE_REMOVED) + $c = q("SELECT * FROM channel WHERE channel_id = %d AND channel_removed = 0 LIMIT 1", + intval($this->auth->owner_id) ); - $r = q("SELECT flags, folder, data FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1", + $is_photo = false; + $album = ''; + + $r = q("SELECT flags, folder, os_storage, filename, is_photo FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1", dbesc($this->data['hash']), intval($c[0]['channel_id']) ); if ($r) { - if ($r[0]['flags'] & ATTACH_FLAG_OS) { - $fname = dbunescbin($r[0]['data']); - $f = 'store/' . $this->auth->owner_nick . '/' . (($fname) ? $fname : ''); - // @todo check return value and set $size directly - @file_put_contents($f, $data); - $size = @filesize($f); - logger('filename: ' . $f . ' size: ' . $size, LOGGER_DEBUG); - } else { + if (intval($r[0]['os_storage'])) { + $d = q("select folder, data from attach where hash = '%s' and uid = %d limit 1", + dbesc($this->data['hash']), + intval($c[0]['channel_id']) + ); + if($d) { + if($d[0]['folder']) { + $f1 = q("select * from attach where is_dir = 1 and hash = '%s' and uid = %d limit 1", + dbesc($d[0]['folder']), + intval($c[0]['channel_id']) + ); + if($f1) { + $album = $f1[0]['filename']; + $direct = $f1[0]; + } + } + $fname = dbunescbin($d[0]['data']); + $f = 'store/' . $this->auth->owner_nick . '/' . (($fname) ? $fname : ''); + // @todo check return value and set $size directly + @file_put_contents($f, $data); + $size = @filesize($f); + logger('filename: ' . $f . ' size: ' . $size, LOGGER_DEBUG); + } + $gis = @getimagesize($f); + logger('getimagesize: ' . print_r($gis,true), LOGGER_DATA); + if(($gis) && ($gis[2] === IMAGETYPE_GIF || $gis[2] === IMAGETYPE_JPEG || $gis[2] === IMAGETYPE_PNG)) { + $is_photo = 1; + } + } + else { + // this shouldn't happen any more $r = q("UPDATE attach SET data = '%s' WHERE hash = '%s' AND uid = %d", dbescbin(stream_get_contents($data)), dbesc($this->data['hash']), @@ -133,13 +158,20 @@ class RedFile extends DAV\Node implements DAV\IFile { // returns now() $edited = datetime_convert(); - $d = q("UPDATE attach SET filesize = '%s', edited = '%s' WHERE hash = '%s' AND uid = %d", + $d = q("UPDATE attach SET filesize = '%s', is_photo = %d, edited = '%s' WHERE hash = '%s' AND uid = %d", dbesc($size), + intval($is_photo), dbesc($edited), dbesc($this->data['hash']), intval($c[0]['channel_id']) ); + if($is_photo) { + require_once('include/photos.php'); + $args = array( 'resource_id' => $this->data['hash'], 'album' => $album, 'os_path' => $f, 'filename' => $r[0]['filename'], 'getimagesize' => $gis, 'directory' => $direct ); + $p = photo_upload($c[0],get_app()->get_observer(),$args); + } + // update the folder's lastmodified timestamp $e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d", dbesc($edited), @@ -178,8 +210,9 @@ class RedFile extends DAV\Node implements DAV\IFile { */ public function get() { logger('get file ' . basename($this->name), LOGGER_DEBUG); + logger('os_path: ' . $this->os_path, LOGGER_DATA); - $r = q("SELECT data, flags, filename, filetype FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1", + $r = q("SELECT data, flags, os_storage, filename, filetype FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1", dbesc($this->data['hash']), intval($this->data['uid']) ); @@ -192,7 +225,7 @@ class RedFile extends DAV\Node implements DAV\IFile { header('Content-type: text/plain'); } - if ($r[0]['flags'] & ATTACH_FLAG_OS ) { + if (intval($r[0]['os_storage'])) { $f = 'store/' . $this->auth->owner_nick . '/' . (($this->os_path) ? $this->os_path . '/' : '') . dbunescbin($r[0]['data']); return fopen($f, 'rb'); } @@ -271,7 +304,7 @@ class RedFile extends DAV\Node implements DAV\IFile { } if ($this->auth->owner_id !== $this->auth->channel_id) { - if (($this->auth->observer !== $this->data['creator']) || ($this->data['flags'] & ATTACH_FLAG_DIR)) { + if (($this->auth->observer !== $this->data['creator']) || intval($this->data['is_dir'])) { throw new DAV\Exception\Forbidden('Permission denied.'); } } diff --git a/include/acl_selectors.php b/include/acl_selectors.php index ae740b281..cb2266473 100644 --- a/include/acl_selectors.php +++ b/include/acl_selectors.php @@ -171,10 +171,9 @@ function contact_select($selname, $selclass, $preselected = false, $size = 4, $p $o .= "<select name=\"{$selname}[]\" id=\"$selclass\" class=\"$selclass\" multiple=\"multiple\" size=\"$size\" $tabindex >\r\n"; $r = q("SELECT abook_id, xchan_name, xchan_url, xchan_photo_s from abook left join xchan on abook_xchan = xchan_hash - where abook_flags = 0 or not ( abook_flags & %d )>0 and abook_channel = %d + where abook_self = 0 and abook_channel = %d $sql_extra ORDER BY xchan_name ASC ", - intval(ABOOK_FLAG_SELF), intval(local_channel()) ); diff --git a/include/activities.php b/include/activities.php index ca8863e51..df43f1f6f 100644 --- a/include/activities.php +++ b/include/activities.php @@ -21,7 +21,10 @@ function profile_activity($changed, $value) { $arr['uid'] = local_channel(); $arr['aid'] = $self['channel_account_id']; $arr['owner_xchan'] = $arr['author_xchan'] = $self['xchan_hash']; - $arr['item_flags'] = ITEM_WALL|ITEM_ORIGIN|ITEM_THREAD_TOP; + + $arr['item_wall'] = 1; + $arr['item_origin'] = 1; + $arr['item_thread_top'] = 1; $arr['verb'] = ACTIVITY_UPDATE; $arr['obj_type'] = ACTIVITY_OBJ_PROFILE; diff --git a/include/api.php b/include/api.php index 027779558..a77bf15f7 100644 --- a/include/api.php +++ b/include/api.php @@ -318,7 +318,7 @@ require_once('include/items.php'); return False; } else { $user = local_channel(); - $extra_query = " AND abook_channel = %d AND (abook_flags & " . ABOOK_FLAG_SELF . " )>0 "; + $extra_query = " AND abook_channel = %d AND abook_self = 1 "; } } @@ -336,7 +336,7 @@ require_once('include/items.php'); return False; } - if($uinfo[0]['abook_flags'] & ABOOK_FLAG_SELF) { + if(intval($uinfo[0]['abook_self'])) { $usr = q("select * from channel where channel_id = %d limit 1", intval(api_user()) ); @@ -344,13 +344,14 @@ require_once('include/items.php'); intval(api_user()) ); + $item_normal = item_normal(); + // count public wall messages $r = q("SELECT COUNT(`id`) as `count` FROM `item` WHERE `uid` = %d - AND ( item_flags & %d )>0 and item_restrict = 0 + AND item_wall = 1 $item_normal AND `allow_cid`='' AND `allow_gid`='' AND `deny_cid`='' AND `deny_gid`=''", - intval($usr[0]['channel_id']), - intval(ITEM_WALL) + intval($usr[0]['channel_id']) ); $countitms = $r[0]['count']; } @@ -367,21 +368,20 @@ require_once('include/items.php'); // count friends if($usr) { $r = q("SELECT COUNT(abook_id) as `count` FROM abook - WHERE abook_channel = %d AND abook_flags = 0 ", + WHERE abook_channel = %d AND abook_self = 0 ", intval($usr[0]['channel_id']) ); $countfriends = $r[0]['count']; $countfollowers = $r[0]['count']; } - $r = q("SELECT count(`id`) as `count` FROM item where ( item_flags & %d )>0 and uid = %d and item_restrict = 0", - intval($uinfo[0]['channel_id']), - intval(ITEM_STARRED) + $r = q("SELECT count(`id`) as `count` FROM item where item_starred = 1 and uid = %d " . item_normal(), + intval($uinfo[0]['channel_id']) ); $starred = $r[0]['count']; - if(! ($uinfo[0]['abook_flags'] & ABOOK_FLAG_SELF)) { + if(! intval($uinfo[0]['abook_self'])) { $countfriends = 0; $countfollowers = 0; $starred = 0; @@ -389,7 +389,7 @@ require_once('include/items.php'); $ret = Array( 'id' => intval($uinfo[0]['abook_id']), - 'self' => (($uinfo[0]['abook_flags'] & ABOOK_FLAG_SELF) ? 1 : 0), + 'self' => (intval($uinfo[0]['abook_self']) ? 1 : 0), 'uid' => intval($uinfo[0]['abook_channel']), 'guid' => $uinfo[0]['xchan_hash'], 'name' => (($uinfo[0]['xchan_name']) ? $uinfo[0]['xchan_name'] : substr($uinfo[0]['xchan_addr'],0,strpos($uinfo[0]['xchan_addr'],'@'))), @@ -896,11 +896,62 @@ require_once('include/items.php'); api_register_func('api/red/item/new','red_item_new', true); + function red_item(&$a, $type) { + + if (api_user() === false) { + logger('api_red_item_new: no user'); + return false; + } + + if($_REQUEST['mid']) { + $arr = array('mid' => $_REQUEST['mid']); + } + elseif($_REQUEST['item_id']) { + $arr = array('item_id' => $_REQUEST['item_id']); + } + else + json_return_and_die(array()); + + $arr['start'] = 0; + $arr['records'] = 999999; + $arr['item_type'] = '*'; + + $i = items_fetch($arr,$a->get_channel(),get_observer_hash()); + + if(! $i) + json_return_and_die(array()); + + $ret = array(); + $tmp = array(); + $str = ''; + foreach($i as $ii) { + $tmp[] = encode_item($ii,true); + if($str) + $str .= ','; + $str .= $ii['id']; + } + $ret['item'] = $tmp; + if($str) { + $r = q("select item_id.*, item.mid from item_id left join item on item_id.iid = item.id where item.id in ( $str ) "); + + if($r) + $ret['item_id'] = $r; + } + + json_return_and_die($ret); + } + + api_register_func('api/red/item/full','red_item', true); + + + function api_get_status($xchan_hash) { require_once('include/security.php'); + $item_normal = item_normal(); + $lastwall = q("SELECT * from item where - item_private = 0 and item_restrict = 0 + item_private = 0 $item_normal and author_xchan = '%s' and allow_cid = '' and allow_gid = '' and deny_cid = '' and deny_gid = '' and verb = '%s' @@ -962,9 +1013,10 @@ require_once('include/items.php'); // get last public message require_once('include/security.php'); + $item_normal = item_normal(); $lastwall = q("SELECT * from item where - item_private = 0 and item_restrict = 0 + item_private = 0 $item_normal and author_xchan = '%s' and allow_cid = '' and allow_gid = '' and deny_cid = '' and deny_gid = '' and verb = '%s' @@ -1035,9 +1087,10 @@ require_once('include/items.php'); $user_info = api_get_user($a); require_once('include/security.php'); + $item_normal = item_normal(); $lastwall = q("SELECT * from item where 1 - and item_private != 0 and item_restrict = 0 + and item_private != 0 $item_normal and author_xchan = '%s' and allow_cid = '' and allow_gid = '' and deny_cid = '' and deny_gid = '' and verb = '%s' @@ -1138,7 +1191,9 @@ require_once('include/items.php'); $sql_extra .= " and item_private = 0 "; } - $r = q("SELECT * from item WHERE uid = %d and item_restrict = 0 + $item_normal = item_normal(); + + $r = q("SELECT * from item WHERE uid = %d $item_normal $sql_extra AND id > %d ORDER BY received DESC LIMIT %d ,%d ", @@ -1157,7 +1212,7 @@ require_once('include/items.php'); // at the network timeline just mark everything seen. if (api_user() == $user_info['uid']) { - $r = q("UPDATE `item` SET item_unseen = 0 where item_unseen = 1 and uid = %d", + $r = q("UPDATE item SET item_unseen = 0 WHERE item_unseen = 1 and uid = %d", intval($user_info['uid']) ); } @@ -1204,11 +1259,12 @@ require_once('include/items.php'); if ($max_id > 0) $sql_extra = 'AND `item`.`id` <= '.intval($max_id); require_once('include/security.php'); + $item_normal = item_normal(); - $r = q("select * from item where item_restrict = 0 - and allow_cid = '' and allow_gid = '' + $r = q("select * from item where allow_cid = '' and allow_gid = '' and deny_cid = '' and deny_gid = '' - and item_private = 0 + and item_private = 0 + $item_normal and uid = " . $sys['channel_id'] . " $sql_extra AND id > %d group by mid @@ -1264,7 +1320,8 @@ require_once('include/items.php'); else $sql_extra .= " AND `item`.`id` = %d"; - $r = q("select * from item where item_restrict = 0 $sql_extra", + $item_normal = item_normal(); + $r = q("select * from item where true $item_normal $sql_extra", intval($id) ); xchan_query($r,true); @@ -1304,7 +1361,9 @@ require_once('include/items.php'); $observer = get_app()->get_observer(); - $r = q("SELECT * from item where item_restrict = 0 and id = %d limit 1", + $item_normal = item_normal(); + + $r = q("SELECT * from item where and id = %d $item_normal limit 1", intval($id) ); @@ -1577,39 +1636,36 @@ require_once('include/items.php'); $itemid = intval($_REQUEST['id']); } - $item = q("SELECT * FROM item WHERE id = %d AND uid = %d", - intval($itemid), - intval(api_user()) + $item = q("SELECT * FROM item WHERE id = %d AND uid = %d", + intval($itemid), + intval(api_user()) ); if (! $item) return false; - switch($action){ - case "create": - - $flags = $item[0]['item_flags'] | ITEM_STARRED; - - break; - case "destroy": - - $flags = $item[0]['item_flags'] | (~ ITEM_STARRED); - break; - default: - return false; - } - - $r = q("UPDATE item SET item_flags = %d where id = %d and uid = %d", - intval($flags), + switch($action){ + case "create": + $flags = $item[0]['item_starred'] = 1; + break; + case "destroy": + $flags = $item[0]['item_starred'] = 0; + break; + default: + return false; + } + + $r = q("UPDATE item SET item_starred = %d where id = %d and uid = %d", + intval($flags), intval($itemid), intval(api_user()) ); if(! $r) return false; - $item = q("SELECT * FROM item WHERE id = %d AND uid = %d", - intval($itemid), - intval(api_user()) + $item = q("SELECT * FROM item WHERE id = %d AND uid = %d", + intval($itemid), + intval(api_user()) ); xchan_query($item,true); @@ -1667,12 +1723,13 @@ require_once('include/items.php'); $sql_extra .= " and item_private = 0 "; } - $r = q("SELECT * from item WHERE uid = %d and item_restrict = 0 - and ( item_flags & %d ) > 0 $sql_extra + $item_normal = item_normal(); + + $r = q("SELECT * from item WHERE uid = %d $item_normal + and item_starred = 1 $sql_extra AND id > %d ORDER BY received DESC LIMIT %d ,%d ", intval($user_info['uid']), - intval(ITEM_STARRED), intval($since_id), intval($start), intval($count) @@ -1864,7 +1921,7 @@ require_once('include/items.php'); 'in_reply_to_user_id' => $in_reply_to_user_id, 'in_reply_to_screen_name' => $in_reply_to_screen_name, 'geo' => '', - 'favorited' => (($item['item_flags'] & ITEM_STARRED) ? true : false), + 'favorited' => (intval($item['item_starred']) ? true : false), 'user' => $status_user , 'statusnet_html' => trim(prepare_text($item['body'],$item['mimetype'])), @@ -1959,7 +2016,7 @@ require_once('include/items.php'); if($qtype == 'followers') $sql_extra = sprintf(" AND ( abook_my_perms & %d )>0 and not ( abook_their_perms & %d )>0 ", intval(PERMS_W_STREAM), intval(PERMS_W_STREAM)); - $r = q("SELECT abook_id FROM abook where abook_flags = 0 and abook_channel = %d $sql_extra", + $r = q("SELECT abook_id FROM abook where abook_self = 0 and abook_channel = %d $sql_extra", intval(api_user()) ); @@ -2012,7 +2069,7 @@ require_once('include/items.php'); 'broughtbyurl' => '', 'timezone' => 'UTC', 'closed' => $closed, 'inviteonly' => 'false', 'private' => $private, 'textlimit' => $textlimit, 'sslserver' => $sslserver, 'ssl' => $ssl, 'shorturllength' => '30', - 'redmatrix' => array( + 'hubzilla' => array( 'PLATFORM_NAME' => PLATFORM_NAME, 'RED_VERSION' => RED_VERSION, 'ZOT_REVISION' => ZOT_REVISION, @@ -2075,7 +2132,7 @@ require_once('include/items.php'); if($qtype == 'followers') $sql_extra = sprintf(" AND ( abook_my_perms & %d )>0 and not ( abook_their_perms & %d )>0 ", intval(PERMS_W_STREAM), intval(PERMS_W_STREAM)); - $r = q("SELECT abook_id FROM abook where abook_flags = 0 and abook_channel = %d $sql_extra", + $r = q("SELECT abook_id FROM abook where abook_self = 0 and abook_channel = %d $sql_extra", intval(api_user()) ); diff --git a/include/apps.php b/include/apps.php index 504641102..661fc2163 100644 --- a/include/apps.php +++ b/include/apps.php @@ -264,18 +264,37 @@ function app_install($uid,$app) { else $x = app_store($app); - if($x['success']) - return $x['app_id']; + if($x['success']) { + $r = q("select * from app where app_id = '%s' and app_channel = %d limit 1", + dbesc($x['app_id']), + intval($uid) + ); + if($r) + build_sync_packet($uid,array('app' => $r[0])); + return $x['app_id']; + } return false; } function app_destroy($uid,$app) { + + if($uid && $app['guid']) { + + $x = q("select * from app where app_id = '%s' and app_channel = %d limit 1", + dbesc($app['guid']), + intval($uid) + ); + $x[0]['app_deleted'] = 1; + + $r = q("delete from app where app_id = '%s' and app_channel = %d", dbesc($app['guid']), intval($uid) ); + + build_sync_packet($uid,array('app' => $x)); } } @@ -325,7 +344,7 @@ function app_store($arr) { return $ret; if($arr['photo'] && ! strstr($arr['photo'],z_root())) { - $x = import_profile_photo($arr['photo'],get_observer_hash(),true); + $x = import_xchan_photo($arr['photo'],get_observer_hash(),true); $arr['photo'] = $x[1]; } @@ -342,7 +361,9 @@ function app_store($arr) { $darray['app_page'] = ((x($arr,'page')) ? escape_tags($arr['page']) : ''); $darray['app_requires'] = ((x($arr,'requires')) ? escape_tags($arr['requires']) : ''); - $r = q("insert into app ( app_id, app_sig, app_author, app_name, app_desc, app_url, app_photo, app_version, app_channel, app_addr, app_price, app_page, app_requires ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s' )", + $created = datetime_convert(); + + $r = q("insert into app ( app_id, app_sig, app_author, app_name, app_desc, app_url, app_photo, app_version, app_channel, app_addr, app_price, app_page, app_requires, app_created, app_edited ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s' )", dbesc($darray['app_id']), dbesc($darray['app_sig']), dbesc($darray['app_author']), @@ -355,7 +376,9 @@ function app_store($arr) { dbesc($darray['app_addr']), dbesc($darray['app_price']), dbesc($darray['app_page']), - dbesc($darray['app_requires']) + dbesc($darray['app_requires']), + dbesc($created), + dbesc($created) ); if($r) { $ret['success'] = true; @@ -378,7 +401,7 @@ function app_update($arr) { return $ret; if($arr['photo'] && ! strstr($arr['photo'],z_root())) { - $x = import_profile_photo($arr['photo'],get_observer_hash(),true); + $x = import_xchan_photo($arr['photo'],get_observer_hash(),true); $arr['photo'] = $x[1]; } @@ -393,7 +416,9 @@ function app_update($arr) { $darray['app_page'] = ((x($arr,'page')) ? escape_tags($arr['page']) : ''); $darray['app_requires'] = ((x($arr,'requires')) ? escape_tags($arr['requires']) : ''); - $r = q("update app set app_sig = '%s', app_author = '%s', app_name = '%s', app_desc = '%s', app_url = '%s', app_photo = '%s', app_version = '%s', app_addr = '%s', app_price = '%s', app_page = '%s', app_requires = '%s' where app_id = '%s' and app_channel = %d", + $edited = datetime_convert(); + + $r = q("update app set app_sig = '%s', app_author = '%s', app_name = '%s', app_desc = '%s', app_url = '%s', app_photo = '%s', app_version = '%s', app_addr = '%s', app_price = '%s', app_page = '%s', app_requires = '%s', app_edited = '%s' where app_id = '%s' and app_channel = %d", dbesc($darray['app_sig']), dbesc($darray['app_author']), dbesc($darray['app_name']), @@ -405,6 +430,7 @@ function app_update($arr) { dbesc($darray['app_price']), dbesc($darray['app_page']), dbesc($darray['app_requires']), + dbesc($edited), dbesc($darray['app_id']), intval($darray['app_channel']) ); diff --git a/include/attach.php b/include/attach.php index 4bbda9530..39fdb5c3a 100644 --- a/include/attach.php +++ b/include/attach.php @@ -150,10 +150,11 @@ function attach_count_files($channel_id, $observer, $hash = '', $filename = '', if($filetype) $sql_extra .= protect_sprintf(" and filetype like '@" . dbesc($filetype) . "@' "); - $r = q("select id from attach where uid = %d $sql_extra", + $r = q("select id, uid, folder from attach where uid = %d $sql_extra", intval($channel_id) ); + $ret['success'] = ((is_array($r)) ? true : false); $ret['results'] = ((is_array($r)) ? count($r) : false); @@ -202,7 +203,7 @@ function attach_list_files($channel_id, $observer, $hash = '', $filename = '', $ // Retrieve all columns except 'data' - $r = q("select id, aid, uid, hash, filename, filetype, filesize, revision, folder, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid from attach where uid = %d $sql_extra $orderby $limit", + $r = q("select id, aid, uid, hash, filename, filetype, filesize, revision, folder, os_storage, is_dir, is_photo, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid from attach where uid = %d $sql_extra $orderby $limit", intval($channel_id) ); @@ -262,12 +263,40 @@ function attach_by_hash($hash, $rev = 0) { return $ret; } + if($r[0]['folder']) { + $x = attach_can_view_folder($r[0]['uid'],get_observer_hash(),$r[0]['folder']); + if(! $x) { + $ret['message'] = t('Permission denied.'); + return $ret; + } + } + $ret['success'] = true; $ret['data'] = $r[0]; return $ret; } +function attach_can_view_folder($uid,$ob_hash,$folder_hash) { + + $sql_extra = permissions_sql($uid,$ob_hash); + $hash = $folder_hash; + $result = false; + + do { + $r = q("select folder from attach where hash = '%s' and uid = %d $sql_extra", + dbesc($hash), + intval($uid) + ); + if(! $r) + return false; + $hash = $r[0]['folder']; + } + while($hash); + return true; +} + + /** * @brief Find an attachment by hash and revision. * @@ -310,7 +339,7 @@ function attach_by_hash_nodata($hash, $rev = 0) { // Now we'll see if we can access the attachment - $r = q("select id, aid, uid, hash, creator, filename, filetype, filesize, revision, folder, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid from attach where uid = %d and hash = '%s' $sql_extra limit 1", + $r = q("select id, aid, uid, hash, creator, filename, filetype, filesize, revision, folder, os_storage, is_photo, is_dir, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid from attach where uid = %d and hash = '%s' $sql_extra limit 1", intval($r[0]['uid']), dbesc($hash) ); @@ -320,6 +349,15 @@ function attach_by_hash_nodata($hash, $rev = 0) { return $ret; } + if($r[0]['folder']) { + $x = attach_can_view_folder($r[0]['uid'],get_observer_hash(),$r[0]['folder']); + if(! $x) { + $ret['message'] = t('Permission denied.'); + return $ret; + } + } + + $ret['success'] = true; $ret['data'] = $r[0]; @@ -340,17 +378,68 @@ function attach_by_hash_nodata($hash, $rev = 0) { * @param string $options (optional) one of update, replace, revision * @param array $arr (optional) associative array */ + +/** + * A lot going on in this function, and some of it is old cruft and some is new cruft + * and the entire thing probably needs to be refactored. It started out just storing + * files, before we had DAV. It was made extensible to do extra stuff like edit an + * existing file or optionally store a separate revision using $options to choose between different + * storage models. Along the way we moved from + * DB data storage to file system storage. + * Then DAV came along and used different upload methods depending on whether the + * file was stored as a DAV directory object or updated as a file object. One of these + * is essentially an update and the other is basically an upload, but doesn't use the traditional PHP + * upload workflow. + * Then came hubzilla and we tried to merge photo functionality with the file storage. Most of + * that integration occurs within this function. + * This required overlap with the old photo_upload stuff and photo albums were + * completely different concepts from directories which needed to be reconciled somehow. + * The old revision stuff is kind of orphaned currently. There's new revision stuff for photos + * which attaches (2) etc. onto the name, but doesn't integrate with the attach table revisioning. + * That's where it sits currently. I repeat it needs to be refactored, and this note is here + * for future explorers and those who may be doing that work to understand where it came + * from and got to be the monstrosity of tangled unrelated code that it currently is. + */ + function attach_store($channel, $observer_hash, $options = '', $arr = null) { + require_once('include/photos.php'); + + + call_hooks('photo_upload_begin',$arr); + $ret = array('success' => false); $channel_id = $channel['channel_id']; $sql_options = ''; + $source = (($arr) ? $arr['source'] : ''); + $album = (($arr) ? $arr['album'] : ''); + $newalbum = (($arr) ? $arr['newalbum'] : ''); + $hash = (($arr && $arr['hash']) ? $arr['hash'] : null); + $upload_path = (($arr && $arr['directory']) ? $arr['directory'] : ''); + + $observer = array(); + + if($observer_hash) { + $x = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($observer_hash) + ); + if($x) + $observer = $x[0]; + } + + logger('arr: ' . print_r($arr,true)); - if(! perm_is_allowed($channel_id,get_observer_hash(), 'write_storage')) { + if(! perm_is_allowed($channel_id,$observer_hash, 'write_storage')) { $ret['message'] = t('Permission denied.'); return $ret; } + $str_group_allow = perms2str($arr['group_allow']); + $str_contact_allow = perms2str($arr['contact_allow']); + $str_group_deny = perms2str($arr['group_deny']); + $str_contact_deny = perms2str($arr['contact_deny']); + + // The 'update' option sets db values without uploading a new attachment // 'replace' replaces the existing uploaded data // 'revision' creates a new revision with new upload data @@ -358,23 +447,42 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { // revise or update must provide $arr['hash'] of the thing to revise/update - if($options !== 'update') { - if(! x($_FILES,'userfile')) { - $ret['message'] = t('No source file.'); - return $ret; - } + if($options === 'import') { + $src = $arr['src']; + $filename = $arr['filename']; + $filesize = @filesize($src); + $hash = $arr['resource_id']; + } + elseif($options !== 'update') { + $f = array('src' => '', 'filename' => '', 'filesize' => 0, 'type' => ''); - $src = $_FILES['userfile']['tmp_name']; - $filename = basename($_FILES['userfile']['name']); - $filesize = intval($_FILES['userfile']['size']); + call_hooks('photo_upload_file',$f); + call_hooks('attach_upload_file',$f); + + if (x($f,'src') && x($f,'filesize')) { + $src = $f['src']; + $filename = $f['filename']; + $filesize = $f['filesize']; + $type = $f['type']; + + } else { + + if(! x($_FILES,'userfile')) { + $ret['message'] = t('No source file.'); + return $ret; + } + + $src = $_FILES['userfile']['tmp_name']; + $filename = basename($_FILES['userfile']['name']); + $filesize = intval($_FILES['userfile']['size']); + } } $existing_size = 0; if($options === 'replace') { - /** @BUG $replace is undefined here */ $x = q("select id, hash, filesize from attach where id = %d and uid = %d limit 1", - intval($replace), + intval($arr['id']), intval($channel_id) ); if(! $x) { @@ -391,7 +499,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { if($options === 'update' && $arr && array_key_exists('revision',$arr)) $sql_options = " and revision = " . intval($arr['revision']) . " "; - $x = q("select id, aid, uid, filename, filetype, filesize, hash, revision, folder, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid from attach where hash = '%s' and uid = %d $sql_options limit 1", + $x = q("select id, aid, uid, filename, filetype, filesize, hash, revision, folder, os_storage, is_photo, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid from attach where hash = '%s' and uid = %d $sql_options limit 1", dbesc($arr['hash']), intval($channel_id) ); @@ -402,6 +510,120 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { $hash = $x[0]['hash']; } + + + $def_extension = ''; + $is_photo = 0; + $gis = @getimagesize($src); + logger('getimagesize: ' . print_r($gis,true), LOGGER_DATA); + if(($gis) && ($gis[2] === IMAGETYPE_GIF || $gis[2] === IMAGETYPE_JPEG || $gis[2] === IMAGETYPE_PNG)) { + $is_photo = 1; + if($gis[2] === IMAGETYPE_GIF) + $def_extension = '.gif'; + if($gis[2] === IMAGETYPE_JPEG) + $def_extension = '.jpg'; + if($gis[2] === IMAGETYPE_PNG) + $def_extension = '.png'; + + } + + $pathname = ''; + + if($is_photo) { + if($newalbum) + $pathname = filepath_macro($newalbum); + else + $pathname = filepath_macro($album); + } + else { + $pathname = filepath_macro($upload_path); + } + + $darr = array('pathname' => $pathname); + + // if we need to create a directory, use the channel default permissions. + + $darr['allow_cid'] = $channel['allow_cid']; + $darr['allow_gid'] = $channel['allow_gid']; + $darr['deny_cid'] = $channel['deny_cid']; + $darr['deny_gid'] = $channel['deny_gid']; + + + $direct = null; + + if($pathname) { + $x = attach_mkdirp($channel, $observer_hash, $darr); + $folder_hash = (($x['success']) ? $x['data']['hash'] : ''); + $direct = (($x['success']) ? $x['data'] : null); + if((! $str_contact_allow) && (! $str_group_allow) && (! $str_contact_deny) && (! $str_group_deny)) { + $str_contact_allow = $x['data']['allow_cid']; + $str_group_allow = $x['data']['allow_gid']; + $str_contact_deny = $x['data']['deny_cid']; + $str_group_deny = $x['data']['deny_gid']; + } + } + else { + $folder_hash = ''; + } + + if((! $options) || ($options === 'import')) { + + // A freshly uploaded file. Check for duplicate and resolve with the channel's overwrite settings. + + $r = q("select filename, id, hash, filesize from attach where filename = '%s' and folder = '%s' ", + dbesc($filename), + dbesc($folder_hash) + ); + if($r) { + $overwrite = get_pconfig($channel_id,'system','overwrite_dup_files'); + if($overwrite) { + $options = 'replace'; + $existing_id = $x[0]['id']; + $existing_size = intval($x[0]['filesize']); + $hash = $x[0]['hash']; + } + else { + if(strpos($filename,'.') !== false) { + $basename = substr($filename,0,strrpos($filename,'.')); + $ext = substr($filename,strrpos($filename,'.')); + } + else { + $basename = $filename; + $ext = $def_extension; + } + + $r = q("select filename from attach where ( filename = '%s' OR filename like '%s' ) and folder = '%s' ", + dbesc($basename . $ext), + dbesc($basename . '(%)' . $ext), + dbesc($folder_hash) + ); + + if($r) { + $x = 1; + + do { + $found = false; + foreach($r as $rr) { + if($rr['filename'] === $basename . '(' . $x . ')' . $ext) { + $found = true; + break; + } + } + if($found) + $x++; + } + while($found); + $filename = $basename . '(' . $x . ')' . $ext; + } + else + $filename = $basename . $ext; + } + } + } + + if(! $hash) + $hash = random_string(); + // Check storage limits if($options !== 'update') { $maxfilesize = get_config('system','maxfilesize'); @@ -409,6 +631,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { if(($maxfilesize) && ($filesize > $maxfilesize)) { $ret['message'] = sprintf( t('File exceeds size limit of %d'), $maxfilesize); @unlink($src); + call_hooks('photo_upload_end',$ret); return $ret; } @@ -421,40 +644,67 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { if(($r) && (($r[0]['total'] + $filesize) > ($limit - $existing_size))) { $ret['message'] = upgrade_message(true) . sprintf(t("You have reached your limit of %1$.0f Mbytes attachment storage."), $limit / 1024000); @unlink($src); + call_hooks('photo_upload_end',$ret); return $ret; } } - $mimetype = z_mime_content_type($filename); + $mimetype = ((isset($type) && $type) ? $type : z_mime_content_type($filename)); } - if(! isset($hash)) - $hash = random_string(); + $os_basepath = 'store/' . $channel['channel_address'] . '/' ; + $os_relpath = ''; - $created = datetime_convert(); + if($folder_hash) { + $curr = find_folder_hash_by_attach_hash($channel_id,$folder_hash,true); + if($curr) + $os_relpath .= $curr . '/'; + $os_relpath .= $folder_hash . '/'; + } + + $os_relpath .= $hash; + + if($src) + @file_put_contents($os_basepath . $os_relpath,@file_get_contents($src)); + + if(array_key_exists('created', $arr)) + $created = $arr['created']; + else + $created = datetime_convert(); + + if(array_key_exists('edited', $arr)) + $edited = $arr['edited']; + else + $edited = $created; if($options === 'replace') { - $r = q("update attach set filename = '%s', filetype = '%s', filesize = %d, data = '%s', edited = '%s' where id = %d and uid = %d", + $r = q("update attach set filename = '%s', filetype = '%s', folder = '%s', filesize = %d, os_storage = %d, is_photo = %d, data = '%s', edited = '%s' where id = %d and uid = %d", dbesc($filename), dbesc($mimetype), + dbesc($folder_hash), intval($filesize), - dbescbin(@file_get_contents($src)), + intval(1), + intval($is_photo), + dbesc($os_relpath), dbesc($created), intval($existing_id), intval($channel_id) ); } elseif($options === 'revise') { - $r = q("insert into attach ( aid, uid, hash, creator, filename, filetype, filesize, revision, data, created, edited, allow_cid, allow_gid, deny_cid, deny_gid ) - VALUES ( %d, %d, '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", + $r = q("insert into attach ( aid, uid, hash, creator, filename, filetype, folder, filesize, revision, os_storage, is_photo, data, created, edited, allow_cid, allow_gid, deny_cid, deny_gid ) + VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", intval($x[0]['aid']), intval($channel_id), dbesc($x[0]['hash']), - dbesc(get_observer_hash()), + dbesc($observer_hash), dbesc($filename), dbesc($mimetype), + dbesc($folder_hash), intval($filesize), intval($x[0]['revision'] + 1), - dbescbin(@file_get_contents($src)), + intval(1), + intval($is_photo), + dbesc($os_relpath), dbesc($created), dbesc($created), dbesc($x[0]['allow_cid']), @@ -464,11 +714,14 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { ); } elseif($options === 'update') { - $r = q("update attach set filename = '%s', filetype = '%s', edited = '%s', + $r = q("update attach set filename = '%s', filetype = '%s', folder = '%s', edited = '%s', os_storage = %d, is_photo = %d, allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where id = %d and uid = %d", dbesc((array_key_exists('filename',$arr)) ? $arr['filename'] : $x[0]['filename']), dbesc((array_key_exists('filetype',$arr)) ? $arr['filetype'] : $x[0]['filetype']), + dbesc(($folder_hash) ? $folder_hash : $x[0]['folder']), dbesc($created), + dbesc((array_key_exists('os_storage',$arr)) ? $arr['os_storage'] : $x[0]['os_storage']), + dbesc((array_key_exists('is_photo',$arr)) ? $arr['is_photo'] : $x[0]['is_photo']), dbesc((array_key_exists('allow_cid',$arr)) ? $arr['allow_cid'] : $x[0]['allow_cid']), dbesc((array_key_exists('allow_gid',$arr)) ? $arr['allow_gid'] : $x[0]['allow_gid']), dbesc((array_key_exists('deny_cid',$arr)) ? $arr['deny_cid'] : $x[0]['deny_cid']), @@ -478,49 +731,90 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { ); } else { - $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, filetype, filesize, revision, data, created, edited, allow_cid, allow_gid,deny_cid, deny_gid ) - VALUES ( %d, %d, '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", + + $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, filetype, folder, filesize, revision, os_storage, is_photo, data, created, edited, allow_cid, allow_gid,deny_cid, deny_gid ) + VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", intval($channel['channel_account_id']), intval($channel_id), dbesc($hash), dbesc(get_observer_hash()), dbesc($filename), dbesc($mimetype), + dbesc($folder_hash), intval($filesize), intval(0), - dbescbin(@file_get_contents($src)), + intval(1), + intval($is_photo), + dbesc($os_relpath), dbesc($created), dbesc($created), - dbesc(($arr && array_key_exists('allow_cid',$arr)) ? $arr['allow_cid'] : '<' . $channel['channel_hash'] . '>'), - 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'] : '') + dbesc(($arr && array_key_exists('allow_cid',$arr)) ? $arr['allow_cid'] : $str_contact_allow), + dbesc(($arr && array_key_exists('allow_gid',$arr)) ? $arr['allow_gid'] : $str_group_allow), + dbesc(($arr && array_key_exists('deny_cid',$arr)) ? $arr['deny_cid'] : $str_contact_deny), + dbesc(($arr && array_key_exists('deny_gid',$arr)) ? $arr['deny_gid'] : $str_group_deny) ); } + if($is_photo) { + + $args = array( 'source' => $source, 'visible' => 0, 'resource_id' => $hash, 'album' => basename($pathname), 'os_path' => $os_basepath . $os_relpath, 'filename' => $filename, 'getimagesize' => $gis, 'directory' => $direct); + if($arr['contact_allow']) + $args['contact_allow'] = $arr['contact_allow']; + if($arr['group_allow']) + $args['group_allow'] = $arr['group_allow']; + if($arr['contact_deny']) + $args['contact_deny'] = $arr['contact_deny']; + if($arr['group_deny']) + $args['group_deny'] = $arr['group_deny']; + if(array_key_exists('allow_cid',$arr)) + $args['allow_cid'] = $arr['allow_cid']; + if(array_key_exists('allow_gid',$arr)) + $args['allow_gid'] = $arr['allow_gid']; + if(array_key_exists('deny_cid',$arr)) + $args['deny_cid'] = $arr['deny_cid']; + if(array_key_exists('deny_gid',$arr)) + $args['deny_gid'] = $arr['deny_gid']; + + $args['created'] = $created; + $args['edited'] = $edited; + if($arr['item']) + $args['item'] = $arr['item']; + + $p = photo_upload($channel,$observer,$args); + if($p['success']) { + $ret['body'] = $p['body']; + } + } + if($options !== 'update') @unlink($src); if(! $r) { $ret['message'] = t('File upload failed. Possible system limit or action terminated.'); + call_hooks('photo_upload_end',$ret); return $ret; } // Caution: This re-uses $sql_options set further above - $r = q("select id, aid, uid, hash, creator, filename, filetype, filesize, revision, folder, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid from attach where uid = %d and hash = '%s' $sql_options limit 1", + $r = q("select id, aid, uid, hash, creator, filename, filetype, filesize, revision, folder, os_storage, is_photo, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid from attach where uid = %d and hash = '%s' $sql_options limit 1", intval($channel_id), dbesc($hash) ); if(! $r) { $ret['message'] = t('Stored file could not be verified. Upload failed.'); + call_hooks('photo_upload_end',$ret); return $ret; } + $ret['success'] = true; $ret['data'] = $r[0]; - + if(! $is_photo) { + // This would've been called already with a success result in photos_upload() if it was a photo. + call_hooks('photo_upload_end',$ret); + } return $ret; } @@ -552,10 +846,9 @@ function z_readdir($channel_id, $observer_hash, $pathname, $parent_hash = '') { if(count($paths) > 1) { $curpath = array_shift($paths); - $r = q("select hash, id from attach where uid = %d and filename = '%s' and (flags & %d )>0 " . permissions_sql($channel_id) . " limit 1", + $r = q("select hash, id, is_dir from attach where uid = %d and filename = '%s' and is_dir != 0 " . permissions_sql($channel_id) . " limit 1", intval($channel_id), - dbesc($curpath), - intval(ATTACH_FLAG_DIR) + dbesc($curpath) ); if(! $r) { $ret['message'] = t('Path not available.'); @@ -568,11 +861,10 @@ function z_readdir($channel_id, $observer_hash, $pathname, $parent_hash = '') { else $paths = array($pathname); - $r = q("select id, aid, uid, hash, creator, filename, filetype, filesize, revision, folder, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid from attach where id = %d and folder = '%s' and filename = '%s' and (flags & %d )>0 " . permissions_sql($channel_id), + $r = q("select id, aid, uid, hash, creator, filename, filetype, filesize, revision, folder, is_photo, is_dir, os_storage, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid from attach where id = %d and folder = '%s' and filename = '%s' and is_dir != 0 " . permissions_sql($channel_id), intval($channel_id), dbesc($parent_hash), - dbesc($paths[0]), - intval(ATTACH_FLAG_DIR) + dbesc($paths[0]) ); if(! $r) { $ret['message'] = t('Path not available.'); @@ -594,7 +886,7 @@ function z_readdir($channel_id, $observer_hash, $pathname, $parent_hash = '') { * * \e string \b filename * * \e string \b folder hash of parent directory, empty string for root directory * - Optional: - * * \e string \b hash precumputed hash for this node + * * \e string \b hash precomputed hash for this node * * \e tring \b allow_cid * * \e string \b allow_gid * * \e string \b deny_cid @@ -605,6 +897,7 @@ function attach_mkdir($channel, $observer_hash, $arr = null) { $ret = array('success' => false); $channel_id = $channel['channel_id']; + $sql_options = ''; $basepath = 'store/' . $channel['channel_address']; @@ -629,13 +922,23 @@ function attach_mkdir($channel, $observer_hash, $arr = null) { // 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", + $r = q("select id, hash, is_dir, flags 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) { + if(array_key_exists('force',$arr) && intval($arr['force']) + && (intval($r[0]['is_dir']))) { + $ret['success'] = true; + $r = q("select * from attach where id = %d limit 1", + intval($r[0]['id']) + ); + if($r) + $ret['data'] = $r[0]; + return $ret; + } $ret['message'] = t('duplicate filename or path'); return $ret; } @@ -651,11 +954,10 @@ function attach_mkdir($channel, $observer_hash, $arr = null) { $sql_options = permissions_sql($channel['channel_id']); do { - $r = q("select filename, hash, flags, folder from attach where uid = %d and hash = '%s' and ( flags & %d )>0 + $r = q("select filename, hash, flags, is_dir, folder from attach where uid = %d and hash = '%s' and is_dir != 0 $sql_options limit 1", intval($channel['channel_id']), - dbesc($lfile), - intval(ATTACH_FLAG_DIR) + dbesc($lfile) ); if(! $r) { @@ -666,7 +968,7 @@ function attach_mkdir($channel, $observer_hash, $arr = null) { if($lfile) $lpath = $r[0]['hash'] . '/' . $lpath; $lfile = $r[0]['folder']; - } while ( ($r[0]['folder']) && ($r[0]['flags'] & ATTACH_FLAG_DIR)) ; + } while ( ($r[0]['folder']) && intval($r[0]['is_dir'])) ; $path = $basepath . '/' . $lpath; } else @@ -676,8 +978,8 @@ function attach_mkdir($channel, $observer_hash, $arr = null) { $created = datetime_convert(); - $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, filetype, filesize, revision, folder, flags, data, created, edited, allow_cid, allow_gid, deny_cid, deny_gid ) - VALUES ( %d, %d, '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", + $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, filetype, filesize, revision, folder, os_storage, is_dir, data, created, edited, allow_cid, allow_gid, deny_cid, deny_gid ) + VALUES ( %d, %d, '%s', '%s', '%s', '%s', %d, %d, '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", intval($channel['channel_account_id']), intval($channel_id), dbesc($arr['hash']), @@ -687,7 +989,8 @@ function attach_mkdir($channel, $observer_hash, $arr = null) { intval(0), intval(0), dbesc($arr['folder']), - intval(ATTACH_FLAG_DIR|ATTACH_FLAG_OS), + intval(1), + intval(1), dbesc($path), dbesc($created), dbesc($created), @@ -700,7 +1003,6 @@ function attach_mkdir($channel, $observer_hash, $arr = null) { if($r) { if(os_mkdir($path, STORAGE_DEFAULT_PERMISSIONS, true)) { $ret['success'] = true; - $ret['data'] = $arr; // update the parent folder's lastmodified timestamp $e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d", @@ -708,6 +1010,13 @@ function attach_mkdir($channel, $observer_hash, $arr = null) { dbesc($arr['folder']), intval($channel_id) ); + + $z = q("select * from attach where hash = '%s' and uid = %d and is_dir = 1 limit 1", + dbesc($arr['hash']), + intval($channel_id) + ); + if($z) + $ret['data'] = $z[0]; } else { logger('attach_mkdir: ' . mkdir . ' ' . $path . ' failed.'); @@ -722,6 +1031,95 @@ function attach_mkdir($channel, $observer_hash, $arr = null) { } /** + * @brief Create directory (recursive). + * + * @param array $channel channel array of owner + * @param string $observer_hash hash of current observer + * @param array $arr parameter array to fulfil request + * - Required: + * * \e string \b pathname + * * \e string \b folder hash of parent directory, empty string for root directory + * - Optional: + * * \e string \b allow_cid + * * \e string \b allow_gid + * * \e string \b deny_cid + * * \e string \b deny_gid + * @return array + */ +function attach_mkdirp($channel, $observer_hash, $arr = null) { + + $ret = array('success' => false); + $channel_id = $channel['channel_id']; + + $sql_options = ''; + + $basepath = 'store/' . $channel['channel_address']; + + logger('attach_mkdirp: basepath: ' . $basepath); + + if(! is_dir($basepath)) + os_mkdir($basepath,STORAGE_DEFAULT_PERMISSIONS, true); + + if(! perm_is_allowed($channel_id, $observer_hash, 'write_storage')) { + $ret['message'] = t('Permission denied.'); + return $ret; + } + + if(! $arr['pathname']) { + $ret['message'] = t('Empty pathname'); + return $ret; + } + + $paths = explode('/',$arr['pathname']); + if(! $paths) { + $ret['message'] = t('Empty path'); + return $ret; + } + + $current_parent = ''; + + foreach($paths as $p) { + if(! $p) + continue; + $arx = array( + 'filename' => $p, + 'folder' => $current_parent, + 'force' => 1 + ); + if(array_key_exists('allow_cid',$arr)) + $arx['allow_cid'] = $arr['allow_cid']; + if(array_key_exists('deny_cid',$arr)) + $arx['deny_cid'] = $arr['deny_cid']; + if(array_key_exists('allow_gid',$arr)) + $arx['allow_gid'] = $arr['allow_gid']; + if(array_key_exists('deny_gid',$arr)) + $arx['deny_gid'] = $arr['deny_gid']; + + $x = attach_mkdir($channel, $observer_hash, $arx); + if($x['success']) { + $current_parent = $x['data']['hash']; + } + else { + $ret['message'] = $x['message']; + return $ret; + } + } + if(isset($x)) { + $ret['success'] = true; + $ret['data'] = $x['data']; + } + + return $ret; + +} + + + + + + + +/** * @brief Changes permissions of a file. * * @param int $channel_id @@ -734,7 +1132,7 @@ function attach_mkdir($channel, $observer_hash, $arr = null) { */ function attach_change_permissions($channel_id, $resource, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $recurse = false) { - $r = q("select hash, flags from attach where hash = '%s' and uid = %d limit 1", + $r = q("select hash, flags, is_dir, is_photo from attach where hash = '%s' and uid = %d limit 1", dbesc($resource), intval($channel_id) ); @@ -742,9 +1140,9 @@ function attach_change_permissions($channel_id, $resource, $allow_cid, $allow_gi if(! $r) return; - if($r[0]['flags'] & ATTACH_FLAG_DIR) { + if(intval($r[0]['is_dir'])) { if($recurse) { - $r = q("select hash, flags from attach where folder = '%s' and uid = %d", + $r = q("select hash, flags, is_dir from attach where folder = '%s' and uid = %d", dbesc($resource), intval($channel_id) ); @@ -764,6 +1162,16 @@ function attach_change_permissions($channel_id, $resource, $allow_cid, $allow_gi dbesc($resource), intval($channel_id) ); + if($r[0]['is_photo']) { + $x = q("update photo set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where resource_id = '%s' and uid = %d", + dbesc($allow_cid), + dbesc($allow_gid), + dbesc($deny_cid), + dbesc($deny_gid), + dbesc($resource), + intval($channel_id) + ); + } } /** @@ -778,15 +1186,16 @@ function attach_change_permissions($channel_id, $resource, $allow_cid, $allow_gi * The hash to delete * @return void */ -function attach_delete($channel_id, $resource) { +function attach_delete($channel_id, $resource, $is_photo = 0) { $c = q("SELECT channel_address FROM channel WHERE channel_id = %d LIMIT 1", intval($channel_id) ); $channel_address = (($c) ? $c[0]['channel_address'] : 'notfound'); + $photo_sql = (($is_photo) ? " and is_photo = 1 " : ''); - $r = q("SELECT hash, flags, folder FROM attach WHERE hash = '%s' AND uid = %d limit 1", + $r = q("SELECT hash, flags, is_dir, folder FROM attach WHERE hash = '%s' AND uid = %d $photo_sql limit 1", dbesc($resource), intval($channel_id) ); @@ -798,8 +1207,8 @@ function attach_delete($channel_id, $resource) { $object = get_file_activity_object($channel_id, $resource, $cloudpath); // If resource is a directory delete everything in the directory recursive - if($r[0]['flags'] & ATTACH_FLAG_DIR) { - $x = q("SELECT hash, flags FROM attach WHERE folder = '%s' AND uid = %d", + if(intval($r[0]['is_dir'])) { + $x = q("SELECT hash, os_storage, is_dir, flags FROM attach WHERE folder = '%s' AND uid = %d", dbesc($resource), intval($channel_id) ); @@ -811,7 +1220,7 @@ function attach_delete($channel_id, $resource) { } // delete a file from filesystem - if($r[0]['flags'] & ATTACH_FLAG_OS) { + if(intval($r[0]['os_storage'])) { $y = q("SELECT data FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1", dbesc($resource), intval($channel_id) @@ -873,11 +1282,10 @@ function get_cloudpath($arr) { $lfile = $arr['folder']; do { - $r = q("select filename, hash, flags, folder from attach where uid = %d and hash = '%s' and ( flags & %d )>0 + $r = q("select filename, hash, flags, is_dir, folder from attach where uid = %d and hash = '%s' and is_dir != 0 limit 1", intval($arr['uid']), - dbesc($lfile), - intval(ATTACH_FLAG_DIR) + dbesc($lfile) ); if(! $r) @@ -887,7 +1295,7 @@ function get_cloudpath($arr) { $lpath = $r[0]['filename'] . '/' . $lpath; $lfile = $r[0]['folder']; - } while ( ($r[0]['folder']) && ($r[0]['flags'] & ATTACH_FLAG_DIR)); + } while ( ($r[0]['folder']) && intval($r[0]['is_dir'])); $path .= $lpath; } @@ -932,14 +1340,19 @@ function get_parent_cloudpath($channel_id, $channel_name, $attachHash) { * The hash of the attachment * @return string */ -function find_folder_hash_by_attach_hash($channel_id, $attachHash) { +function find_folder_hash_by_attach_hash($channel_id, $attachHash, $recurse = false) { + +logger('attach_hash: ' . $attachHash); $r = q("SELECT folder FROM attach WHERE uid = %d AND hash = '%s' LIMIT 1", intval($channel_id), dbesc($attachHash) ); $hash = ''; - if ($r) { - $hash = $r[0]['folder']; + if($r && $r[0]['folder']) { + if($recurse) + $hash = find_folder_hash_by_attach_hash($channel_id,$r[0]['folder'],true) . '/' . $r[0]['folder']; + else + $hash = $r[0]['folder']; } return $hash; } @@ -1011,7 +1424,7 @@ function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid, //filter out receivers which do not have permission to view filestorage $arr_allow_cid = check_list_permissions($channel_id, $arr_allow_cid, 'view_storage'); - $is_dir = (($object['flags'] & ATTACH_FLAG_DIR) ? true : false); + $is_dir = (intval($object['is_dir']) ? true : false); //do not send activity for folders for now if($is_dir) @@ -1036,9 +1449,13 @@ function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid, $mid = item_message_id(); - $objtype = ACTIVITY_OBJ_FILE; + $arr = array(); + + $arr['item_wall'] = 1; + $arr['item_origin'] = 1; + $arr['item_unseen'] = 1; - $item_flags = ITEM_WALL|ITEM_ORIGIN; + $objtype = ACTIVITY_OBJ_FILE; $private = (($arr_allow_cid[0] || $arr_allow_gid[0] || $arr_deny_cid[0] || $arr_deny_gid[0]) ? 1 : 0); @@ -1077,23 +1494,20 @@ function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid, $u_mid = item_message_id(); - $arr = array(); - $arr['aid'] = get_account_id(); $arr['uid'] = $channel_id; $arr['mid'] = $u_mid; $arr['parent_mid'] = $u_mid; - $arr['item_flags'] = $item_flags; - $arr['item_unseen'] = 1; $arr['author_xchan'] = $poster['xchan_hash']; $arr['owner_xchan'] = $poster['xchan_hash']; $arr['title'] = ''; - $arr['allow_cid'] = perms2str($u_arr_allow_cid); - $arr['allow_gid'] = perms2str($u_arr_allow_gid); - $arr['deny_cid'] = perms2str($u_arr_deny_cid); - $arr['deny_gid'] = perms2str($u_arr_deny_gid); - $arr['item_restrict'] = ITEM_HIDDEN; - $arr['item_private'] = $private; + //updates should be visible to everybody -> perms may have changed + $arr['allow_cid'] = ''; + $arr['allow_gid'] = ''; + $arr['deny_cid'] = ''; + $arr['deny_gid'] = ''; + $arr['item_hidden'] = 1; + $arr['item_private'] = 0; $arr['verb'] = ACTIVITY_UPDATE; $arr['obj_type'] = $objtype; $arr['object'] = $u_jsonobject; @@ -1124,7 +1538,8 @@ function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid, $arr['uid'] = $channel_id; $arr['mid'] = $mid; $arr['parent_mid'] = $mid; - $arr['item_flags'] = $item_flags; + $arr['item_wall'] = 1; + $arr['item_origin'] = 1; $arr['item_unseen'] = 1; $arr['author_xchan'] = $poster['xchan_hash']; $arr['owner_xchan'] = $poster['xchan_hash']; @@ -1133,7 +1548,7 @@ function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid, $arr['allow_gid'] = perms2str($arr_allow_gid); $arr['deny_cid'] = perms2str($arr_deny_cid); $arr['deny_gid'] = perms2str($arr_deny_gid); - $arr['item_restrict'] = ITEM_HIDDEN; + $arr['item_hidden'] = 1; $arr['item_private'] = $private; $arr['verb'] = (($update) ? ACTIVITY_UPDATE : ACTIVITY_POST); $arr['obj_type'] = $objtype; @@ -1165,7 +1580,7 @@ function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid, */ function get_file_activity_object($channel_id, $hash, $cloudpath) { - $x = q("SELECT creator, filename, filetype, filesize, revision, folder, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid FROM attach WHERE uid = %d AND hash = '%s' LIMIT 1", + $x = q("SELECT creator, filename, filetype, filesize, revision, folder, os_storage, is_photo, is_dir, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid FROM attach WHERE uid = %d AND hash = '%s' LIMIT 1", intval($channel_id), dbesc($hash) ); @@ -1193,6 +1608,9 @@ function get_file_activity_object($channel_id, $hash, $cloudpath) { 'revision' => $x[0]['revision'], 'folder' => $x[0]['folder'], 'flags' => $x[0]['flags'], + 'os_storage' => $x[0]['os_storage'], + 'is_photo' => $x[0]['is_photo'], + 'is_dir' => $x[0]['is_dir'], 'created' => $x[0]['created'], 'edited' => $x[0]['edited'], 'allow_cid' => $x[0]['allow_cid'], @@ -1348,3 +1766,16 @@ function in_group($group_id) { return $group_members; } + + +function filepath_macro($s) { + + return str_replace( + array( '%Y', '%m', '%d' ), + array( datetime_convert('UTC',date_default_timezone_get(),'now', 'Y'), + datetime_convert('UTC',date_default_timezone_get(),'now', 'm'), + datetime_convert('UTC',date_default_timezone_get(),'now', 'd') + ), $s); + +} + diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php index 65f8f3ea1..692128087 100644 --- a/include/bb2diaspora.php +++ b/include/bb2diaspora.php @@ -326,7 +326,7 @@ function bb2diaspora_itembody($item, $force_update = false) { $newitem = $item; - if(array_key_exists('item_flags',$item) && ($item['item_flags'] & ITEM_OBSCURED)) { + if(array_key_exists('item_obscured',$item) && intval($item['item_obscured'])) { $key = get_config('system','prvkey'); $b = json_decode($item['body'],true); // if called from diaspora_process_outbound, this decoding has already been done. diff --git a/include/bbcode.php b/include/bbcode.php index 6fc481fff..db5824237 100644 --- a/include/bbcode.php +++ b/include/bbcode.php @@ -12,6 +12,7 @@ require_once('include/hubloc.php'); function tryoembed($match) { $url = ((count($match) == 2) ? $match[1] : $match[2]); + $o = oembed_fetch_url($url); if ($o->type == 'error') @@ -205,16 +206,6 @@ function translate_design_element($type) { return $ret; } -/** - * @brief Returns an QR-code image from a value given in $match[1]. - * - * @param array $match - * @return string HTML img with QR-code of $match[1] - */ -function bb_qr($match) { - return '<img class="zrl" src="' . z_root() . '/photo/qr?f=&qr=' . urlencode($match[1]) . '" alt="' . t('QR code') . '" title="' . htmlspecialchars($match[1],ENT_QUOTES,'UTF-8') . '" />'; -} - function bb_ShareAttributes($match) { @@ -406,10 +397,49 @@ function bb_sanitize_style($input) { return '<span style="' . $css_string_san . '">' . $input[2] . '</span>'; } +function bb_observer($Text) { + + $a = get_app(); + + $observer = $a->get_observer(); + + 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); + } + } + + $channel = $a->get_channel(); + + if (strpos($Text,'[/channel]') !== false) { + if ($channel) { + $Text = preg_replace("/\[channel\=1\](.*?)\[\/channel\]/ism", '$1', $Text); + $Text = preg_replace("/\[channel\=0\].*?\[\/channel\]/ism", '', $Text); + } else { + $Text = preg_replace("/\[channel\=1\].*?\[\/channel\]/ism", '', $Text); + $Text = preg_replace("/\[channel\=0\](.*?)\[\/channel\]/ism", '$1', $Text); + } + } + + return $Text; +} + + + + + + + // BBcode 2 HTML was written by WAY2WEB.net - // extended to work with Mistpark/Friendica/Red - Mike Macgirvin + // extended to work with Mistpark/Friendica/Redmatrix/Hubzilla - Mike Macgirvin -function bbcode($Text, $preserve_nl = false, $tryoembed = true) { +function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false) { $a = get_app(); @@ -434,8 +464,6 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true) { $Text = preg_replace_callback("/\[pre\](.*?)\[\/pre\]/ism", 'bb_spacefy',$Text); } - - // If we find any event code, turn it into an event. // After we're finished processing the bbcode we'll // replace all of the event code with a reformatted version. @@ -445,7 +473,8 @@ 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 - if(get_config('system','item_cache')) + + if($cache) $observer = false; else $observer = $a->get_observer(); @@ -462,7 +491,7 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true) { } } - if(get_config('system','item_cache')) + if($cache) $channel = false; else $channel = $a->get_channel(); @@ -544,10 +573,6 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true) { $Text = preg_replace("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/$urlchars+)/ism", '$1<a href="$2" >$2</a>', $Text); } - if (strpos($Text,'[/qr]') !== false) { - $Text = preg_replace_callback("/\[qr\](.*?)\[\/qr\]/ism", 'bb_qr', $Text); - } - if (strpos($Text,'[/share]') !== false) { $Text = preg_replace_callback("/\[share(.*?)\](.*?)\[\/share\]/ism", 'bb_ShareAttributes', $Text); } @@ -884,35 +909,35 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true) { } // Youtube extensions - if (strpos($Text,'[youtube]') !== false) { - if ($tryoembed) { - $Text = preg_replace_callback("/\[youtube\](https?:\/\/www.youtube.com\/watch\?v\=.*?)\[\/youtube\]/ism", 'tryoembed', $Text); - $Text = preg_replace_callback("/\[youtube\](www.youtube.com\/watch\?v\=.*?)\[\/youtube\]/ism", 'tryoembed', $Text); - $Text = preg_replace_callback("/\[youtube\](https?:\/\/youtu.be\/.*?)\[\/youtube\]/ism", 'tryoembed', $Text); - } - $Text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/watch\?v\=(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $Text); - $Text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/embed\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $Text); - $Text = preg_replace("/\[youtube\]https?:\/\/youtu.be\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $Text); - - if ($tryoembed) - $Text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", '<iframe width="' . $a->videowidth . '" height="' . $a->videoheight . '" src="http://www.youtube.com/embed/$1" frameborder="0"></iframe>', $Text); - else - $Text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", "http://www.youtube.com/watch?v=$1", $Text); - } - if (strpos($Text,'[vimeo]') !== false) { - if ($tryoembed) { - $Text = preg_replace_callback("/\[vimeo\](https?:\/\/player.vimeo.com\/video\/[0-9]+).*?\[\/vimeo\]/ism", 'tryoembed', $Text); - $Text = preg_replace_callback("/\[vimeo\](https?:\/\/vimeo.com\/[0-9]+).*?\[\/vimeo\]/ism", 'tryoembed', $Text); - } - - $Text = preg_replace("/\[vimeo\]https?:\/\/player.vimeo.com\/video\/([0-9]+)(.*?)\[\/vimeo\]/ism", '[vimeo]$1[/vimeo]', $Text); - $Text = preg_replace("/\[vimeo\]https?:\/\/vimeo.com\/([0-9]+)(.*?)\[\/vimeo\]/ism", '[vimeo]$1[/vimeo]', $Text); - - if ($tryoembed) - $Text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", '<iframe width="' . $a->videowidth . '" height="' . $a->videoheight . '" src="http://player.vimeo.com/video/$1" frameborder="0" ></iframe>', $Text); - else - $Text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", "http://vimeo.com/$1", $Text); - } +// if (strpos($Text,'[youtube]') !== false) { +// if ($tryoembed) { +// $Text = preg_replace_callback("/\[youtube\](https?:\/\/www.youtube.com\/watch\?v\=.*?)\[\/youtube\]/ism", 'tryoembed', $Text); +// $Text = preg_replace_callback("/\[youtube\](www.youtube.com\/watch\?v\=.*?)\[\/youtube\]/ism", 'tryoembed', $Text); +// $Text = preg_replace_callback("/\[youtube\](https?:\/\/youtu.be\/.*?)\[\/youtube\]/ism", 'tryoembed', $Text); +// } +// $Text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/watch\?v\=(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $Text); +// $Text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/embed\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $Text); +// $Text = preg_replace("/\[youtube\]https?:\/\/youtu.be\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $Text); + +// if ($tryoembed) +// $Text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", '<iframe width="' . $a->videowidth . '" height="' . $a->videoheight . '" src="http://www.youtube.com/embed/$1" frameborder="0"></iframe>', $Text); +// else +// $Text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", "http://www.youtube.com/watch?v=$1", $Text); +// } +// if (strpos($Text,'[vimeo]') !== false) { +// if ($tryoembed) { +// $Text = preg_replace_callback("/\[vimeo\](https?:\/\/player.vimeo.com\/video\/[0-9]+).*?\[\/vimeo\]/ism", 'tryoembed', $Text); +// $Text = preg_replace_callback("/\[vimeo\](https?:\/\/vimeo.com\/[0-9]+).*?\[\/vimeo\]/ism", 'tryoembed', $Text); +// } + +// $Text = preg_replace("/\[vimeo\]https?:\/\/player.vimeo.com\/video\/([0-9]+)(.*?)\[\/vimeo\]/ism", '[vimeo]$1[/vimeo]', $Text); +// $Text = preg_replace("/\[vimeo\]https?:\/\/vimeo.com\/([0-9]+)(.*?)\[\/vimeo\]/ism", '[vimeo]$1[/vimeo]', $Text); + +// if ($tryoembed) +// $Text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", '<iframe width="' . $a->videowidth . '" height="' . $a->videoheight . '" src="http://player.vimeo.com/video/$1" frameborder="0" ></iframe>', $Text); +// else +// $Text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", "http://vimeo.com/$1", $Text); +// } // oembed tag $Text = oembed_bbcode2html($Text); @@ -969,15 +994,3 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true) { return $Text; } -/** - * This function exists as a short-term solution to folks linking to private images from their /cloud in - * their profiles, which brings up a login dialogue in the directory when that entry is viewed. - * The long term solution is to separate the web file browser from DAV so that you'll never see a - * login prompt (though the resource may return a permission denied). - */ - - - -function strip_bbimage($s) { - return preg_replace("/\[[zi]mg(.*?)\](.*?)\[\/[zi]mg\]/ism", '', $s); -} diff --git a/include/chat.php b/include/chat.php index 05bb02bb9..81c5c5d62 100644 --- a/include/chat.php +++ b/include/chat.php @@ -91,6 +91,8 @@ function chatroom_destroy($channel,$arr) { return $ret; } + build_sync_packet($channel['channel_id'],array('chatroom' => $r)); + q("delete from chatroom where cr_id = %d", intval($r[0]['cr_id']) ); diff --git a/include/checksites.php b/include/checksites.php new file mode 100644 index 000000000..e9c08c202 --- /dev/null +++ b/include/checksites.php @@ -0,0 +1,62 @@ +<?php /** @file */ + +require_once('boot.php'); +require_once('include/cli_startup.php'); +require_once('include/zot.php'); +require_once('include/hubloc.php'); + + + +function checksites_run($argv, $argc){ + + + cli_startup(); + $a = get_app(); + + logger('checksites: start'); + + if(($argc > 1) && ($argv[1])) + $site_id = $argv[1]; + + if($site_id) + $sql_options = " and site_url = '" . dbesc($argv[1]) . "' "; + + $days = intval(get_config('system','sitecheckdays')); + if($days < 1) + $days = 30; + + $r = q("select * from site where site_dead = 0 and site_update < %s - INTERVAL %s and site_type = %d $sql_options ", + db_utcnow(), db_quoteinterval($days . ' DAY'), + intval(SITE_TYPE_ZOT) + ); + + if(! $r) + return; + + foreach($r as $rr) { + if(! strcasecmp($rr['site_url'],z_root())) + continue; + + $x = ping_site($rr['site_url']); + if($x['success']) { + logger('checksites: ' . $rr['site_url']); + q("update site set site_update = '%s' where site_url = '%s' ", + dbesc(datetime_convert()), + dbesc($rr['site_url']) + ); + } + else { + logger('marking dead site: ' . $x['message']); + q("update site set site_dead = 1 where site_url = '%s' ", + dbesc($rr['site_url']) + ); + } + } + + return; +} + +if (array_search(__file__,get_included_files())===0){ + checksites_run($argv,$argc); + killme(); +} diff --git a/include/comanche.php b/include/comanche.php index 49b910bdb..9585a6578 100644 --- a/include/comanche.php +++ b/include/comanche.php @@ -5,7 +5,7 @@ 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 +// On submit, the pdl_select value (which is the mid of an item with item_type = ITEM_TYPE_PDL) is stored in // the webpage's resource_id, with resource_type 'pdl'. // Then when displaying a webpage, we can see if it has a pdl attached. If not we'll diff --git a/include/contact_widgets.php b/include/contact_widgets.php index a02fea523..a60b8b1c3 100644 --- a/include/contact_widgets.php +++ b/include/contact_widgets.php @@ -71,14 +71,17 @@ function categories_widget($baseurl,$selected = '') { if(! feature_enabled($a->profile['profile_uid'],'categories')) return ''; + $item_normal = item_normal(); + $terms = array(); $r = q("select distinct(term.term) from term join item on term.oid = item.id where item.uid = %d and term.uid = item.uid and term.type = %d - and item.author_xchan = '%s' - and item.item_restrict = 0 + and item.owner_xchan = '%s' + and item.item_wall = 1 + $item_normal order by term.term asc", intval($a->profile['profile_uid']), intval(TERM_CATEGORY), diff --git a/include/conversation.php b/include/conversation.php index 8bbb87e2c..0f6f8685b 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -96,7 +96,7 @@ function localize_item(&$item){ if(! $item['object']) return; - if($item['item_flags'] & ITEM_THREAD_TOP) + if(intval($item['item_thread_top'])) return; $obj = json_decode_plus($item['object']); @@ -356,21 +356,12 @@ function localize_item(&$item){ } } */ - // add sparkle links to appropriate permalinks - -// $x = stristr($item['plink'],'/display/'); -// if($x) { -// $sparkle = false; -// $y = best_link_url($item,$sparkle,true); - // if($sparkle) -// $item['plink'] = $y . '?f=&url=' . $item['plink']; -// } // if item body was obscured and we changed it, re-obscure it // FIXME - we need a better filter than just the string 'data'; try and // match the fact that it's json encoded - if(($item['item_flags'] & ITEM_OBSCURED) + if(intval($item['item_obscured']) && strlen($item['body']) && (! strpos($item['body'],'data'))) { $item['body'] = json_encode(crypto_encapsulate($item['body'],get_config('system','pubkey'))); } @@ -682,8 +673,8 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ $likebuttons = false; $shareable = false; - $verified = (($item['item_flags'] & ITEM_VERIFIED) ? t('Message signature validated') : ''); - $forged = ((($item['sig']) && (! ($item['item_flags'] & ITEM_VERIFIED))) ? t('Message signature incorrect') : ''); + $verified = (intval($item['item_verified']) ? t('Message signature validated') : ''); + $forged = ((($item['sig']) && (! intval($item['item_verified']))) ? t('Message signature incorrect') : ''); $unverified = ''; @@ -939,7 +930,7 @@ function item_photo_menu($item){ if($contact) { $poke_link = $a->get_baseurl($ssl_state) . '/poke/?f=&c=' . $contact['abook_id']; - if (!($contact['abook_flags'] & ABOOK_FLAG_SELF)) + if (! intval($contact['abook_self'])) $contact_url = $a->get_baseurl($ssl_state) . '/connedit/' . $contact['abook_id']; $posts_link = $a->get_baseurl($ssl_state) . '/network/?cid=' . $contact['abook_id']; @@ -952,9 +943,9 @@ function item_photo_menu($item){ t("View Status") => $status_link, t("View Profile") => $profile_link, t("View Photos") => $photos_link, - t("Matrix Activity") => $posts_link, + t("Activity/Posts") => $posts_link, t("Connect") => $follow_url, - t("Edit Contact") => $contact_url, + t("Edit Connection") => $contact_url, t("Send PM") => $pm_url, t("Poke") => $poke_link ); @@ -1146,6 +1137,7 @@ function status_editor($a, $x, $popup = false) { '$newpost' => 'true', '$baseurl' => $a->get_baseurl(true), '$editselect' => (($plaintext) ? 'none' : '/(profile-jot-text|prvmail-text)/'), + '$pretext' => ((x($x,'pretext')) ? $x['pretext'] : ''), '$geotag' => $geotag, '$nickname' => $x['nickname'], '$ispublic' => t('Visible to <strong>everybody</strong>'), @@ -1188,7 +1180,7 @@ function status_editor($a, $x, $popup = false) { '$pagetitle' => (x($x,'pagetitle') ? $x['pagetitle'] : ''), '$id_select' => $id_select, '$id_seltext' => t('Post as'), - '$writefiles' => (perm_is_allowed($x['profile_uid'], get_observer_hash(), 'post_photos') || perm_is_allowed($x['profile_uid'], get_observer_hash(), 'write_storage')), + '$writefiles' => perm_is_allowed($x['profile_uid'], get_observer_hash(), 'write_storage'), '$bold' => t('Bold'), '$italic' => t('Italic'), '$underline' => t('Underline'), @@ -1397,7 +1389,8 @@ function render_location_default($item) { function prepare_page($item) { $a = get_app(); - $naked = ((get_pconfig($item['uid'],'system','nakedpage')) ? 1 : 0); + $naked = 1; +// $naked = ((get_pconfig($item['uid'],'system','nakedpage')) ? 1 : 0); $observer = $a->get_observer(); //240 chars is the longest we can have before we start hitting problems with suhosin sites $preview = substr(urlencode($item['body']), 0, 240); @@ -1606,7 +1599,7 @@ function profile_tabs($a, $is_owner = false, $nickname = null){ 'id' => 'profile-tab', ); } - if ($p['view_photos']) { + if ($p['view_storage']) { $tabs[] = array( 'label' => t('Photos'), 'url' => $a->get_baseurl() . '/photos/' . $nickname, @@ -1614,11 +1607,9 @@ function profile_tabs($a, $is_owner = false, $nickname = null){ 'title' => t('Photo Albums'), 'id' => 'photo-tab', ); - } - if ($p['view_storage']) { $tabs[] = array( 'label' => t('Files'), - 'url' => $a->get_baseurl() . '/cloud/' . $nickname . ((get_observer_hash()) ? '' : '?f=&davguest=1'), + 'url' => $a->get_baseurl() . '/cloud/' . $nickname, 'sel' => ((argv(0) == 'cloud' || argv(0) == 'sharedwithme') ? 'active' : ''), 'title' => t('Files and Storage'), 'id' => 'files-tab', diff --git a/include/deliver.php b/include/deliver.php index 26739fb06..a338d1a89 100644 --- a/include/deliver.php +++ b/include/deliver.php @@ -15,7 +15,10 @@ function deliver_run($argv, $argc) { logger('deliver: invoked: ' . print_r($argv,true), LOGGER_DATA); + for($x = 1; $x < $argc; $x ++) { + + $dresult = null; $r = q("select * from outq where outq_hash = '%s' limit 1", dbesc($argv[$x]) ); @@ -26,6 +29,8 @@ function deliver_run($argv, $argc) { * If not, reduce the outq_priority. */ + $base = ''; + $h = parse_url($r[0]['outq_posturl']); if($h) { $base = $h['scheme'] . '://' . $h['host'] . (($h['port']) ? ':' . $h['port'] : ''); @@ -50,18 +55,45 @@ function deliver_run($argv, $argc) { continue; } } + else { + + // zot sites should all have a site record, unless they've been dead for as long as + // your site has existed. Since we don't know for sure what these sites are, + // call them unknown + + q("insert into site (site_url, site_update, site_dead, site_type) values ('%s','%s',0,%d) ", + dbesc($base), + dbesc(datetime_convert()), + intval(($r[0]['outq_driver'] === 'post') ? SITE_TYPE_NOTZOT : SITE_TYPE_UNKNOWN) + ); + } } } // "post" queue driver - used for diaspora and friendica-over-diaspora communications. if($r[0]['outq_driver'] === 'post') { + + $result = z_post_url($r[0]['outq_posturl'],$r[0]['outq_msg']); if($result['success'] && $result['return_code'] < 300) { logger('deliver: queue post success to ' . $r[0]['outq_posturl'], LOGGER_DEBUG); + if($base) { + q("update site set site_update = '%s', site_dead = 0 where site_url = '%s' ", + dbesc(datetime_convert()), + dbesc($base) + ); + } + q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s' limit 1", + dbesc('accepted for delivery'), + dbesc(datetime_convert()), + dbesc($argv[$x]) + ); + $y = q("delete from outq where outq_hash = '%s'", dbesc($argv[$x]) ); + } else { logger('deliver: queue post returned ' . $result['return_code'] . ' from ' . $r[0]['outq_posturl'],LOGGER_DEBUG); @@ -98,11 +130,29 @@ function deliver_run($argv, $argc) { } else { $msg = array('body' => json_encode(array('success' => true, 'pickup' => array(array('notify' => $notify,'message' => $m))))); - zot_import($msg,z_root()); + $dresult = zot_import($msg,z_root()); } $r = q("delete from outq where outq_hash = '%s'", dbesc($argv[$x]) ); + if($dresult && is_array($dresult)) { + foreach($dresult as $xx) { + if(is_array($xx) && array_key_exists('message_id',$xx)) { + q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan ) values ( '%s', '%s','%s','%s','%s','%s' ) ", + dbesc($xx['message_id']), + dbesc($xx['location']), + dbesc($xx['recipient']), + dbesc($xx['status']), + dbesc(datetime_convert($xx['date'])), + dbesc($xx['sender']) + ); + } + } + } + + q("delete from dreport where dreport_queue = '%s' limit 1", + dbesc($argv[$x]) + ); } } else { diff --git a/include/deliver_hooks.php b/include/deliver_hooks.php new file mode 100644 index 000000000..f0d6ba1b1 --- /dev/null +++ b/include/deliver_hooks.php @@ -0,0 +1,29 @@ +<?php + + +require_once('include/cli_startup.php'); +require_once('include/zot.php'); + + +function deliver_hooks_run($argv, $argc) { + + cli_startup(); + + $a = get_app(); + + if($argc < 2) + return; + + + $r = q("select * from item where id = '%d'", + intval($argv[1]) + ); + if($r) + call_hooks('notifier_normal',$r[0]); + +} + +if (array_search(__file__,get_included_files())===0){ + deliver_hooks_run($argv,$argc); + killme(); +} diff --git a/include/diaspora.php b/include/diaspora.php deleted file mode 100755 index 61556fd9d..000000000 --- a/include/diaspora.php +++ /dev/null @@ -1,3036 +0,0 @@ -<?php - -require_once('include/crypto.php'); -require_once('include/items.php'); -require_once('include/bb2diaspora.php'); -require_once('include/contact_selectors.php'); -//require_once('include/queue_fn.php'); -//require_once('include/lock.php'); - -function diaspora_dispatch_public($msg) { - - $enabled = intval(get_config('system','diaspora_enabled')); - if(! $enabled) { - logger('mod-diaspora: disabled'); - return; - } - - $sys_disabled = true; - - if(! get_config('system','disable_discover_tab')) { - $sys_disabled = get_config('system','disable_diaspora_discover_tab'); - } - $sys = (($sys_disabled) ? null : get_sys_channel()); - - // find everybody following or allowing this author - - $r = q("SELECT * from channel where channel_id in ( SELECT abook_channel from abook left join xchan on abook_xchan = xchan_hash WHERE xchan_network like '%%diaspora%%' and xchan_addr = '%s' ) and ( channel_pageflags & %d ) = 0 ", - dbesc($msg['author']), - intval(PAGE_REMOVED) - ); - - // also need to look for those following public streams - - if($r) { - foreach($r as $rr) { - logger('diaspora_public: delivering to: ' . $rr['channel_name'] . ' (' . $rr['channel_address'] . ') '); - diaspora_dispatch($rr,$msg); - } - } - else { - if(! $sys) - logger('diaspora_public: no subscribers'); - } - - if($sys) { - $sys['system'] = true; - logger('diaspora_public: delivering to sys.'); - diaspora_dispatch($sys,$msg); - } -} - - - -function diaspora_dispatch($importer,$msg) { - - $ret = 0; - - if(! array_key_exists('system',$importer)) - $importer['system'] = false; - - $enabled = intval(get_config('system','diaspora_enabled')); - if(! $enabled) { - logger('mod-diaspora: disabled'); - return; - } - - $allowed = get_pconfig($importer['channel_id'],'system','diaspora_allowed'); - if($allowed === false) - $allowed = 1; - - if(! intval($allowed)) { - logger('mod-diaspora: disallowed for channel ' . $importer['channel_name']); - return; - } - - // php doesn't like dashes in variable names - - $msg['message'] = str_replace( - array('<activity_streams-photo>','</activity_streams-photo>'), - array('<asphoto>','</asphoto>'), - $msg['message']); - - - $parsed_xml = parse_xml_string($msg['message'],false); - - $xmlbase = $parsed_xml->post; - -// logger('diaspora_dispatch: ' . print_r($xmlbase,true), LOGGER_DATA); - - - if($xmlbase->request) { - $ret = diaspora_request($importer,$xmlbase->request); - } - elseif($xmlbase->status_message) { - $ret = diaspora_post($importer,$xmlbase->status_message,$msg); - } - elseif($xmlbase->profile) { - $ret = diaspora_profile($importer,$xmlbase->profile,$msg); - } - elseif($xmlbase->comment) { - $ret = diaspora_comment($importer,$xmlbase->comment,$msg); - } - elseif($xmlbase->like) { - $ret = diaspora_like($importer,$xmlbase->like,$msg); - } - elseif($xmlbase->asphoto) { - $ret = diaspora_asphoto($importer,$xmlbase->asphoto,$msg); - } - elseif($xmlbase->reshare) { - $ret = diaspora_reshare($importer,$xmlbase->reshare,$msg); - } - elseif($xmlbase->retraction) { - $ret = diaspora_retraction($importer,$xmlbase->retraction,$msg); - } - elseif($xmlbase->signed_retraction) { - $ret = diaspora_signed_retraction($importer,$xmlbase->signed_retraction,$msg); - } - elseif($xmlbase->relayable_retraction) { - $ret = diaspora_signed_retraction($importer,$xmlbase->relayable_retraction,$msg); - } - elseif($xmlbase->photo) { - $ret = diaspora_photo($importer,$xmlbase->photo,$msg); - } - elseif($xmlbase->conversation) { - $ret = diaspora_conversation($importer,$xmlbase->conversation,$msg); - } - elseif($xmlbase->message) { - $ret = diaspora_message($importer,$xmlbase->message,$msg); - } - else { - logger('diaspora_dispatch: unknown message type: ' . print_r($xmlbase,true)); - } - return $ret; -} - - -function diaspora_is_blacklisted($s) { - - $bl1 = get_config('system','blacklisted_sites'); - if(is_array($bl1) && $bl1) { - foreach($bl1 as $bl) { - if($bl && strpos($s,$bl) !== false) { - logger('diaspora_is_blacklisted: blacklisted ' . $s); - return true; - } - } - } - return false; -} - -function diaspora_process_outbound($arr) { - -/* - - We are passed the following array from the notifier, providing everything we need to make delivery decisions. - - diaspora_process_outbound(array( - 'channel' => $channel, - 'env_recips' => $env_recips, - 'recipients' => $recipients, - 'item' => $item, - 'target_item' => $target_item, - 'hub' => $hub, - 'top_level_post' => $top_level_post, - 'private' => $private, - 'followup' => $followup, - 'relay_to_owner' => $relay_to_owner, - 'uplink' => $uplink, - 'cmd' => $cmd, - 'expire' => $expire, - 'mail' => $mail, - 'location' => $location, - 'fsuggest' => $fsuggest, - 'normal_mode' => $normal_mode, - 'packet_type' => $packet_type, - 'walltowall' => $walltowall, - )); -*/ - - - $allowed = get_pconfig($arr['channel']['channel_id'],'system','diaspora_allowed'); - if($allowed === false) - $allowed = 1; - - if(! intval($allowed)) { - logger('mod-diaspora: disallowed for channel ' . $arr['channel']['channel_name']); - return; - } - - - if($arr['location']) - return; - - - $target_item = $arr['target_item']; - - if($target_item && array_key_exists('item_flags',$target_item) && ($target_item['item_flags'] & ITEM_OBSCURED)) { - $key = get_config('system','prvkey'); - if($target_item['title']) - $target_item['title'] = crypto_unencapsulate(json_decode($target_item['title'],true),$key); - if($target_item['body']) - $target_item['body'] = crypto_unencapsulate(json_decode($target_item['body'],true),$key); - } - - - - if($arr['env_recips']) { - $hashes = array(); - - // re-explode the recipients, but only for this hub/pod - - foreach($arr['env_recips'] as $recip) - $hashes[] = "'" . $recip['hash'] . "'"; - - $r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_url = '%s' - and xchan_hash in (" . implode(',', $hashes) . ") and xchan_network in ('diaspora', 'friendica-over-diaspora') ", - dbesc($arr['hub']['hubloc_url']) - ); - - if(! $r) { - logger('diaspora_process_outbound: no recipients'); - return; - } - - foreach($r as $contact) { - - if($arr['mail']) { - diaspora_send_mail($arr['item'],$arr['channel'],$contact); - continue; - } - - if(! $arr['normal_mode']) - continue; - - // special handling for followup to public post - // all other public posts processed as public batches further below - - if((! $arr['private']) && ($arr['followup'])) { - diaspora_send_followup($target_item,$arr['channel'],$contact, true); - continue; - } - - if(! $contact['xchan_pubkey']) - continue; - - if(($target_item['item_restrict'] & ITEM_DELETED) - && (($target_item['mid'] === $target_item['parent_mid']) || $arr['followup'])) { - // send both top-level retractions and relayable retractions for owner to relay - diaspora_send_retraction($target_item,$arr['channel'],$contact); - continue; - } - elseif($arr['followup']) { - // send comments and likes to owner to relay - diaspora_send_followup($target_item,$arr['channel'],$contact); - continue; - } - - elseif($target_item['mid'] !== $target_item['parent_mid']) { - // we are the relay - send comments, likes and relayable_retractions - // (of comments and likes) to our conversants - diaspora_send_relay($target_item,$arr['channel'],$contact); - continue; - } - elseif($arr['top_level_post']) { - diaspora_send_status($target_item,$arr['channel'],$contact); - continue; - } - } - } - else { - // public message - - $contact = $arr['hub']; - - if(($target_item['deleted']) - && ($target_item['mid'] === $target_item['parent_mod'])) { - // top-level retraction - logger('delivery: diaspora retract: ' . $loc); - diaspora_send_retraction($target_item,$arr['channel'],$contact,true); - return; - } - elseif($target_item['mid'] !== $target_item['parent_mid']) { - // we are the relay - send comments, likes and relayable_retractions to our conversants - logger('delivery: diaspora relay: ' . $loc); - diaspora_send_relay($target_item,$arr['channel'],$contact,true); - return; - } - elseif($arr['top_level_post']) { - logger('delivery: diaspora status: ' . $loc); - diaspora_send_status($target_item,$arr['channel'],$contact,true); - return; - } - - } - -} - - -function diaspora_handle_from_contact($contact_hash) { - - logger("diaspora_handle_from_contact: contact id is " . $contact_hash, LOGGER_DEBUG); - - $r = q("SELECT xchan_addr from xchan where xchan_hash = '%s' limit 1", - dbesc($contact_hash) - ); - if($r) { - return $r[0]['xchan_addr']; - } - return false; -} - -function diaspora_get_contact_by_handle($uid,$handle) { - - if(diaspora_is_blacklisted($handle)) - return false; - require_once('include/identity.php'); - - $sys = get_sys_channel(); - if(($sys) && ($sys['channel_id'] == $uid)) { - $r = q("SELECT * FROM xchan where xchan_addr = '%s' limit 1", - dbesc($handle) - ); - } - else { - $r = q("SELECT * FROM abook left join xchan on xchan_hash = abook_xchan where xchan_addr = '%s' and abook_channel = %d limit 1", - dbesc($handle), - intval($uid) - ); - } - - return (($r) ? $r[0] : false); -} - -function find_diaspora_person_by_handle($handle) { - - $person = false; - - if(diaspora_is_blacklisted($handle)) - return false; - - $r = q("select * from xchan where xchan_addr = '%s' limit 1", - dbesc($handle) - ); - if($r) { - $person = $r[0]; - logger('find_diaspora_person_by handle: in cache ' . print_r($r,true), LOGGER_DATA); - } - - if(! $person) { - - // try webfinger. Make sure to distinguish between diaspora, - // redmatrix w/diaspora protocol and friendica w/diaspora protocol. - - $result = discover_by_webbie($handle); - if($result) { - $r = q("select * from xchan where xchan_addr = '%s' limit 1", - dbesc($handle) - ); - if($r) { - $person = $r[0]; - logger('find_diaspora_person_by handle: discovered ' . print_r($r,true), LOGGER_DATA); - } - } - } - - return $person; -} - - -function get_diaspora_key($handle) { - logger('Fetching diaspora key for: ' . $handle, LOGGER_DEBUG); - $r = find_diaspora_person_by_handle($handle); - return(($r) ? $r['xchan_pubkey'] : ''); -} - - -function diaspora_pubmsg_build($msg,$channel,$contact,$prvkey,$pubkey) { - - $a = get_app(); - - logger('diaspora_pubmsg_build: ' . $msg, LOGGER_DATA); - - $handle = $channel['channel_address'] . '@' . get_app()->get_hostname(); - - - $b64url_data = base64url_encode($msg,false); - - $data = str_replace(array("\n","\r"," ","\t"),array('','','',''),$b64url_data); - - $type = 'application/xml'; - $encoding = 'base64url'; - $alg = 'RSA-SHA256'; - - $signable_data = $data . '.' . base64url_encode($type,false) . '.' - . base64url_encode($encoding,false) . '.' . base64url_encode($alg,false) ; - - $signature = rsa_sign($signable_data,$prvkey); - $sig = base64url_encode($signature,false); - -$magic_env = <<< EOT -<?xml version='1.0' encoding='UTF-8'?> -<diaspora xmlns="https://joindiaspora.com/protocol" xmlns:me="http://salmon-protocol.org/ns/magic-env" > - <header> - <author_id>$handle</author_id> - </header> - <me:env> - <me:encoding>base64url</me:encoding> - <me:alg>RSA-SHA256</me:alg> - <me:data type="application/xml">$data</me:data> - <me:sig>$sig</me:sig> - </me:env> -</diaspora> -EOT; - - logger('diaspora_pubmsg_build: magic_env: ' . $magic_env, LOGGER_DATA); - return $magic_env; - -} - - - - -function diaspora_msg_build($msg,$channel,$contact,$prvkey,$pubkey,$public = false) { - $a = get_app(); - - if($public) - return diaspora_pubmsg_build($msg,$channel,$contact,$prvkey,$pubkey); - - logger('diaspora_msg_build: ' . $msg, LOGGER_DATA); - - // without a public key nothing will work - - if(! $pubkey) { - logger('diaspora_msg_build: pubkey missing: contact id: ' . $contact['abook_id']); - return ''; - } - - $inner_aes_key = random_string(32); - $b_inner_aes_key = base64_encode($inner_aes_key); - $inner_iv = random_string(16); - $b_inner_iv = base64_encode($inner_iv); - - $outer_aes_key = random_string(32); - $b_outer_aes_key = base64_encode($outer_aes_key); - $outer_iv = random_string(16); - $b_outer_iv = base64_encode($outer_iv); - - $handle = $channel['channel_address'] . '@' . get_app()->get_hostname(); - - $padded_data = pkcs5_pad($msg,16); - $inner_encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $inner_aes_key, $padded_data, MCRYPT_MODE_CBC, $inner_iv); - - $b64_data = base64_encode($inner_encrypted); - - - $b64url_data = base64url_encode($b64_data,false); - $data = str_replace(array("\n","\r"," ","\t"),array('','','',''),$b64url_data); - - $type = 'application/xml'; - $encoding = 'base64url'; - $alg = 'RSA-SHA256'; - - $signable_data = $data . '.' . base64url_encode($type,false) . '.' - . base64url_encode($encoding,false) . '.' . base64url_encode($alg,false) ; - - logger('diaspora_msg_build: signable_data: ' . $signable_data, LOGGER_DATA); - - $signature = rsa_sign($signable_data,$prvkey); - $sig = base64url_encode($signature,false); - -$decrypted_header = <<< EOT -<decrypted_header> - <iv>$b_inner_iv</iv> - <aes_key>$b_inner_aes_key</aes_key> - <author_id>$handle</author_id> -</decrypted_header> -EOT; - - $decrypted_header = pkcs5_pad($decrypted_header,16); - - $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $outer_aes_key, $decrypted_header, MCRYPT_MODE_CBC, $outer_iv); - - $outer_json = json_encode(array('iv' => $b_outer_iv,'key' => $b_outer_aes_key)); - - $encrypted_outer_key_bundle = ''; - openssl_public_encrypt($outer_json,$encrypted_outer_key_bundle,$pubkey); - - $b64_encrypted_outer_key_bundle = base64_encode($encrypted_outer_key_bundle); - - logger('outer_bundle: ' . $b64_encrypted_outer_key_bundle . ' key: ' . $pubkey, LOGGER_DATA); - - $encrypted_header_json_object = json_encode(array('aes_key' => base64_encode($encrypted_outer_key_bundle), - 'ciphertext' => base64_encode($ciphertext))); - $cipher_json = base64_encode($encrypted_header_json_object); - - $encrypted_header = '<encrypted_header>' . $cipher_json . '</encrypted_header>'; - -$magic_env = <<< EOT -<?xml version='1.0' encoding='UTF-8'?> -<diaspora xmlns="https://joindiaspora.com/protocol" xmlns:me="http://salmon-protocol.org/ns/magic-env" > - $encrypted_header - <me:env> - <me:encoding>base64url</me:encoding> - <me:alg>RSA-SHA256</me:alg> - <me:data type="application/xml">$data</me:data> - <me:sig>$sig</me:sig> - </me:env> -</diaspora> -EOT; - - logger('diaspora_msg_build: magic_env: ' . $magic_env, LOGGER_DATA); - return $magic_env; - -} - -/** - * - * diaspora_decode($importer,$xml) - * array $importer -> from user table - * string $xml -> urldecoded Diaspora salmon - * - * Returns array - * 'message' -> decoded Diaspora XML message - * 'author' -> author diaspora handle - * 'key' -> author public key (converted to pkcs#8) - * - * Author and key are used elsewhere to save a lookup for verifying replies and likes - */ - - -function diaspora_decode($importer,$xml) { - - $public = false; - $basedom = parse_xml_string($xml); - - $children = $basedom->children('https://joindiaspora.com/protocol'); - - if($children->header) { - $public = true; - $author_link = str_replace('acct:','',$children->header->author_id); - } - else { - - $encrypted_header = json_decode(base64_decode($children->encrypted_header)); - - $encrypted_aes_key_bundle = base64_decode($encrypted_header->aes_key); - $ciphertext = base64_decode($encrypted_header->ciphertext); - - $outer_key_bundle = ''; - openssl_private_decrypt($encrypted_aes_key_bundle,$outer_key_bundle,$importer['channel_prvkey']); - - $j_outer_key_bundle = json_decode($outer_key_bundle); - - $outer_iv = base64_decode($j_outer_key_bundle->iv); - $outer_key = base64_decode($j_outer_key_bundle->key); - - $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $outer_key, $ciphertext, MCRYPT_MODE_CBC, $outer_iv); - - - $decrypted = pkcs5_unpad($decrypted); - - /** - * $decrypted now contains something like - * - * <decrypted_header> - * <iv>8e+G2+ET8l5BPuW0sVTnQw==</iv> - * <aes_key>UvSMb4puPeB14STkcDWq+4QE302Edu15oaprAQSkLKU=</aes_key> - -***** OBSOLETE - - * <author> - * <name>Ryan Hughes</name> - * <uri>acct:galaxor@diaspora.pirateship.org</uri> - * </author> - -***** CURRENT - - * <author_id>galaxor@diaspora.priateship.org</author_id> - -***** END DIFFS - - * </decrypted_header> - */ - - logger('decrypted: ' . $decrypted, LOGGER_DATA); - $idom = parse_xml_string($decrypted,false); - - $inner_iv = base64_decode($idom->iv); - $inner_aes_key = base64_decode($idom->aes_key); - - $author_link = str_replace('acct:','',$idom->author_id); - - } - - $dom = $basedom->children(NAMESPACE_SALMON_ME); - - // figure out where in the DOM tree our data is hiding - - if($dom->provenance->data) - $base = $dom->provenance; - elseif($dom->env->data) - $base = $dom->env; - elseif($dom->data) - $base = $dom; - - if(! $base) { - logger('mod-diaspora: unable to locate salmon data in xml '); - http_status_exit(400); - } - - - // Stash the signature away for now. We have to find their key or it won't be good for anything. - $signature = base64url_decode($base->sig); - - // unpack the data - - // strip whitespace so our data element will return to one big base64 blob - $data = str_replace(array(" ","\t","\r","\n"),array("","","",""),$base->data); - - - // stash away some other stuff for later - - $type = $base->data[0]->attributes()->type[0]; - $keyhash = $base->sig[0]->attributes()->keyhash[0]; - $encoding = $base->encoding; - $alg = $base->alg; - - $signed_data = $data . '.' . base64url_encode($type,false) . '.' . base64url_encode($encoding,false) . '.' . base64url_encode($alg,false); - - - // decode the data - $data = base64url_decode($data); - - - if($public) { - $inner_decrypted = $data; - } - else { - - // Decode the encrypted blob - - $inner_encrypted = base64_decode($data); - $inner_decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $inner_aes_key, $inner_encrypted, MCRYPT_MODE_CBC, $inner_iv); - $inner_decrypted = pkcs5_unpad($inner_decrypted); - } - - if(! $author_link) { - logger('mod-diaspora: Could not retrieve author URI.'); - http_status_exit(400); - } - - // Once we have the author URI, go to the web and try to find their public key - // (first this will look it up locally if it is in the fcontact cache) - // This will also convert diaspora public key from pkcs#1 to pkcs#8 - - logger('mod-diaspora: Fetching key for ' . $author_link ); - $key = get_diaspora_key($author_link); - - if(! $key) { - logger('mod-diaspora: Could not retrieve author key.'); - http_status_exit(400); - } - - $verify = rsa_verify($signed_data,$signature,$key); - - if(! $verify) { - logger('mod-diaspora: Message did not verify. Discarding.'); - http_status_exit(400); - } - - logger('mod-diaspora: Message verified.'); - - return array('message' => $inner_decrypted, 'author' => $author_link, 'key' => $key); - -} - - -/* sender is now sharing with recipient */ - -function diaspora_request($importer,$xml) { - - $a = get_app(); - - $sender_handle = unxmlify($xml->sender_handle); - $recipient_handle = unxmlify($xml->recipient_handle); - - if(! $sender_handle || ! $recipient_handle) - return; - - - // Do we already have an abook record? - - $contact = diaspora_get_contact_by_handle($importer['channel_id'],$sender_handle); - - if($contact && $contact['abook_id']) { - - // perhaps we were already sharing with this person. Now they're sharing with us. - // That makes us friends. Maybe. - - // Please note some of these permissions such as PERMS_R_PAGES are impossible for Disapora. - // They cannot authenticate to our system. - - $newperms = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK|PERMS_W_STREAM|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT|PERMS_R_STORAGE|PERMS_R_PAGES; - - $r = q("update abook set abook_their_perms = %d where abook_id = %d and abook_channel = %d", - intval($newperms), - intval($contact['abook_id']), - intval($importer['channel_id']) - ); - - return; - } - - $ret = find_diaspora_person_by_handle($sender_handle); - - if((! $ret) || (! strstr($ret['xchan_network'],'diaspora'))) { - logger('diaspora_request: Cannot resolve diaspora handle ' . $sender_handle . ' for ' . $recipient_handle); - return; - } - - -//FIXME -/* - if(feature_enabled($channel['channel_id'],'premium_channel')) { - $myaddr = $importer['channel_address'] . '@' . get_app()->get_hostname(); - $cnv = random_string(); - $mid = random_string(); - - $msg = t('You have started sharing with a $Projectname premium channel.'); - $msg .= t('$Projectname premium channels are not available for sharing with Diaspora members. This sharing request has been blocked.') . "\r"; - $msg .= t('Please do not reply to this message, as this channel is not sharing with you and any reply will not be seen by the recipient.') . "\r"; - - $created = datetime_convert('UTC','UTC',$item['created'],'Y-m-d H:i:s \U\T\C'); - $signed_text = $mid . ';' . $cnv . ';' . $msg . ';' - . $created . ';' . $myaddr . ';' . $cnv; - - $sig = base64_encode(rsa_sign($signed_text,$importer['channel_prvkey'],'sha256')); - - $conv = array( - 'guid' => xmlify($cnv), - 'subject' => xmlify(t('Sharing request failed.')), - 'created_at' => xmlify($created), - 'diaspora_handle' => xmlify($myaddr), - 'participant_handles' => xmlify($myaddr . ';' . $sender_handle) - ); - - $msg = array( - 'guid' => xmlify($mid), - 'parent_guid' => xmlify($cnv), - 'parent_author_signature' => xmlify($sig), - 'author_signature' => xmlify($sig), - 'text' => xmlify($msg), - 'created_at' => xmlify($created), - 'diaspora_handle' => xmlify($myaddr), - 'conversation_guid' => xmlify($cnv) - ); - - $conv['messages'] = array($msg); - $tpl = get_markup_template('diaspora_conversation.tpl'); - $xmsg = replace_macros($tpl, array('$conv' => $conv)); - - $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($xmsg,$importer,$ret,$importer['channel_prvkey'],$ret['xchan_pubkey'],false))); - - diaspora_transmit($importer,$ret,$slap,false); - return; - } - -*/ -// End FIXME - - - $role = get_pconfig($channel['channel_id'],'system','permissions_role'); - if($role) { - $x = get_role_perms($role); - if($x['perms_auto']) - $default_perms = $x['perms_accept']; - } - if(! $default_perms) - $default_perms = intval(get_pconfig($importer['channel_id'],'system','autoperms')); - - $their_perms = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK|PERMS_W_STREAM|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT|PERMS_R_STORAGE|PERMS_R_PAGES; - - - $closeness = get_pconfig($importer['channel_id'],'system','new_abook_closeness'); - if($closeness === false) - $closeness = 80; - - - $r = q("insert into abook ( abook_account, abook_channel, abook_xchan, abook_my_perms, abook_their_perms, abook_closeness, abook_rating, abook_created, abook_updated, abook_connected, abook_dob, abook_flags) values ( %d, %d, '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', %d )", - intval($importer['channel_account_id']), - intval($importer['channel_id']), - dbesc($ret['xchan_hash']), - intval($default_perms), - intval($their_perms), - intval($closeness), - intval(0), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc(NULL_DATE), - intval(($default_perms) ? 0 : ABOOK_FLAG_PENDING) - ); - - - if($r) { - logger("New Diaspora introduction received for {$importer['channel_name']}"); - - $new_connection = q("select * from abook left join xchan on abook_xchan = xchan_hash left join hubloc on hubloc_hash = xchan_hash where abook_channel = %d and abook_xchan = '%s' order by abook_created desc limit 1", - intval($importer['channel_id']), - dbesc($ret['xchan_hash']) - ); - if($new_connection) { - require_once('include/enotify.php'); - notification(array( - 'type' => NOTIFY_INTRO, - 'from_xchan' => $ret['xchan_hash'], - 'to_xchan' => $importer['channel_hash'], - 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id'], - )); - - - if($default_perms) { - // Send back a sharing notification to them - diaspora_share($importer,$new_connection[0]); - - } - - $clone = array(); - foreach($new_connection[0] as $k => $v) { - if(strpos($k,'abook_') === 0) { - $clone[$k] = $v; - } - } - unset($clone['abook_id']); - unset($clone['abook_account']); - unset($clone['abook_channel']); - - build_sync_packet($importer['channel_id'], array('abook' => array($clone))); - - } - } - - // find the abook record we just created - - $contact_record = diaspora_get_contact_by_handle($importer['channel_id'],$sender_handle); - - if(! $contact_record) { - logger('diaspora_request: unable to locate newly created contact record.'); - return; - } - - /** If there is a default group for this channel, add this member to it */ - - if($importer['channel_default_group']) { - require_once('include/group.php'); - $g = group_rec_byhash($importer['channel_id'],$importer['channel_default_group']); - if($g) - group_add_member($importer['channel_id'],'',$contact_record['xchan_hash'],$g['id']); - } - - return; -} - - - -function diaspora_post($importer,$xml,$msg) { - - $a = get_app(); - $guid = notags(unxmlify($xml->guid)); - $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); - $app = notags(xmlify($xml->provider_display_name)); - - - if($diaspora_handle != $msg['author']) { - logger('diaspora_post: Potential forgery. Message handle is not the same as envelope sender.'); - return 202; - } - - $contact = diaspora_get_contact_by_handle($importer['channel_id'],$diaspora_handle); - if(! $contact) - return; - - - - if(! $app) { - if(strstr($contact['xchan_network'],'friendica')) - $app = 'Friendica'; - else - $app = 'Diaspora'; - } - - - $search_guid = ((strlen($guid) == 64) ? $guid . '%' : $guid); - - $r = q("SELECT id FROM item WHERE uid = %d AND mid like '%s' LIMIT 1", - intval($importer['channel_id']), - dbesc($search_guid) - ); - - if($r) { - // check dates if post editing is implemented - logger('diaspora_post: message exists: ' . $guid); - return; - } - - $created = unxmlify($xml->created_at); - $private = ((unxmlify($xml->public) == 'false') ? 1 : 0); - - $body = diaspora2bb($xml->raw_message); - - if($xml->photo) { - $body = '[img]' . $xml->photo->remote_photo_path . $xml->photo->remote_photo_name . '[/img]' . "\n\n" . $body; - $body = scale_external_images($body); - } - - $maxlen = get_max_import_size(); - - if($maxlen && mb_strlen($body) > $maxlen) { - $body = mb_substr($body,0,$maxlen,'UTF-8'); - logger('message length exceeds max_import_size: truncated'); - } - -//WTF? FIXME - // Add OEmbed and other information to the body -// $body = add_page_info_to_body($body, false, true); - - $datarray = array(); - - - // Look for tags and linkify them - $results = linkify_tags(get_app(), $body, $importer['channel_id'], true); - - $datarray['term'] = array(); - - if($results) { - foreach($results as $result) { - $success = $result['success']; - if($success['replaced']) { - $datarray['term'][] = array( - 'uid' => $importer['channel_id'], - 'type' => $success['termtype'], - 'otype' => TERM_OBJ_POST, - 'term' => $success['term'], - 'url' => $success['url'] - ); - } - } - } - - $cnt = preg_match_all('/@\[url=(.*?)\](.*?)\[\/url\]/ism',$body,$matches,PREG_SET_ORDER); - if($cnt) { - foreach($matches as $mtch) { - $datarray['term'][] = array( - 'uid' => $importer['channel_id'], - 'type' => TERM_MENTION, - 'otype' => TERM_OBJ_POST, - 'term' => $mtch[2], - 'url' => $mtch[1] - ); - } - } - - $cnt = preg_match_all('/@\[zrl=(.*?)\](.*?)\[\/zrl\]/ism',$body,$matches,PREG_SET_ORDER); - if($cnt) { - foreach($matches as $mtch) { - // don't include plustags in the term - $term = ((substr($mtch[2],-1,1) === '+') ? substr($mtch[2],0,-1) : $mtch[2]); - $datarray['term'][] = array( - 'uid' => $importer['channel_id'], - 'type' => TERM_MENTION, - 'otype' => TERM_OBJ_POST, - 'term' => $term, - 'url' => $mtch[1] - ); - } - } - - - - - $plink = service_plink($contact,$guid); - - - $datarray['uid'] = $importer['channel_id']; - - $datarray['verb'] = ACTIVITY_POST; - $datarray['mid'] = $datarray['parent_mid'] = $guid; - - $datarray['changed'] = $datarray['created'] = $datarray['edited'] = datetime_convert('UTC','UTC',$created); - $datarray['item_private'] = $private; - - $datarray['plink'] = $plink; - - $datarray['author_xchan'] = $contact['xchan_hash']; - $datarray['owner_xchan'] = $contact['xchan_hash']; - - $datarray['body'] = $body; - - $datarray['app'] = $app; - - $datarray['item_flags'] = ITEM_THREAD_TOP; - $datarray['item_unseen'] = 1; - - - $tgroup = tgroup_check($importer['channel_id'],$datarray); - - if((! $importer['system']) && (! perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'send_stream')) && (! $tgroup)) { - logger('diaspora_post: Ignoring this author.'); - return 202; - } - - if(! post_is_importable($datarray,$contact)) { - logger('diaspora_post: filtering this author.'); - return 202; - } - - $result = item_store($datarray); - return; - -} - - -function get_diaspora_reshare_xml($url,$recurse = 0) { - - $x = z_fetch_url($url); - if(! $x['success']) - $x = z_fetch_url(str_replace('https://','http://',$url)); - if(! $x['success']) { - logger('get_diaspora_reshare_xml: unable to fetch source url ' . $url); - return; - } - logger('get_diaspora_reshare_xml: source: ' . $x['body'], LOGGER_DEBUG); - - $source_xml = parse_xml_string($x['body'],false); - - if(! $source_xml) { - logger('get_diaspora_reshare_xml: unparseable result from ' . $url); - return ''; - } - - if($source_xml->post->status_message) { - return $source_xml; - } - - // see if it's a reshare of a reshare - - if($source_xml->post->reshare) - $xml = $source_xml->post->reshare; - else - return false; - - if($xml->root_diaspora_id && $xml->root_guid && $recurse < 15) { - $orig_author = notags(unxmlify($xml->root_diaspora_id)); - $orig_guid = notags(unxmlify($xml->root_guid)); - $source_url = 'https://' . substr($orig_author,strpos($orig_author,'@')+1) . '/p/' . $orig_guid . '.xml'; - $y = get_diaspora_reshare_xml($source_url,$recurse+1); - if($y) - return $y; - } - return false; -} - - - -function diaspora_reshare($importer,$xml,$msg) { - - logger('diaspora_reshare: init: ' . print_r($xml,true), LOGGER_DATA); - - $a = get_app(); - $guid = notags(unxmlify($xml->guid)); - $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); - - - if($diaspora_handle != $msg['author']) { - logger('diaspora_post: Potential forgery. Message handle is not the same as envelope sender.'); - return 202; - } - - $contact = diaspora_get_contact_by_handle($importer['channel_id'],$diaspora_handle); - if(! $contact) - return; - - $search_guid = ((strlen($guid) == 64) ? $guid . '%' : $guid); - $r = q("SELECT id FROM item WHERE uid = %d AND mid like '%s' LIMIT 1", - intval($importer['channel_id']), - dbesc($search_guid) - ); - if($r) { - logger('diaspora_reshare: message exists: ' . $guid); - return; - } - - $orig_author = notags(unxmlify($xml->root_diaspora_id)); - $orig_guid = notags(unxmlify($xml->root_guid)); - - $source_url = 'https://' . substr($orig_author,strpos($orig_author,'@')+1) . '/p/' . $orig_guid . '.xml'; - $orig_url = 'https://'.substr($orig_author,strpos($orig_author,'@')+1).'/posts/'.$orig_guid; - - $source_xml = get_diaspora_reshare_xml($source_url); - - if($source_xml->post->status_message) { - $body = diaspora2bb($source_xml->post->status_message->raw_message); - - $orig_author = notags(unxmlify($source_xml->post->status_message->diaspora_handle)); - $orig_guid = notags(unxmlify($source_xml->post->status_message->guid)); - - - // Checking for embedded pictures - if($source_xml->post->status_message->photo->remote_photo_path && - $source_xml->post->status_message->photo->remote_photo_name) { - - $remote_photo_path = notags(unxmlify($source_xml->post->status_message->photo->remote_photo_path)); - $remote_photo_name = notags(unxmlify($source_xml->post->status_message->photo->remote_photo_name)); - - $body = '[img]'.$remote_photo_path.$remote_photo_name.'[/img]'."\n".$body; - - logger('diaspora_reshare: embedded picture link found: '.$body, LOGGER_DEBUG); - } - - $body = scale_external_images($body); - - // Add OEmbed and other information to the body -// $body = add_page_info_to_body($body, false, true); - } - else { - // Maybe it is a reshare of a photo that will be delivered at a later time (testing) - logger('diaspora_reshare: no reshare content found: ' . print_r($source_xml,true)); - $body = ""; - //return; - } - - $maxlen = get_max_import_size(); - - if($maxlen && mb_strlen($body) > $maxlen) { - $body = mb_substr($body,0,$maxlen,'UTF-8'); - logger('message length exceeds max_import_size: truncated'); - } - - $person = find_diaspora_person_by_handle($orig_author); - - if($person) { - $orig_author_name = $person['xchan_name']; - $orig_author_link = $person['xchan_url']; - $orig_author_photo = $person['xchan_photo_m']; - } - - - $created = unxmlify($xml->created_at); - $private = ((unxmlify($xml->public) == 'false') ? 1 : 0); - - $datarray = array(); - - // Look for tags and linkify them - $results = linkify_tags(get_app(), $body, $importer['channel_id'], true); - - $datarray['term'] = array(); - - if($results) { - foreach($results as $result) { - $success = $result['success']; - if($success['replaced']) { - $datarray['term'][] = array( - 'uid' => $importer['channel_id'], - 'type' => $success['termtype'], - 'otype' => TERM_OBJ_POST, - 'term' => $success['term'], - 'url' => $success['url'] - ); - } - } - } - - $cnt = preg_match_all('/@\[url=(.*?)\](.*?)\[\/url\]/ism',$body,$matches,PREG_SET_ORDER); - if($cnt) { - foreach($matches as $mtch) { - $datarray['term'][] = array( - 'uid' => $importer['channel_id'], - 'type' => TERM_MENTION, - 'otype' => TERM_OBJ_POST, - 'term' => $mtch[2], - 'url' => $mtch[1] - ); - } - } - - $cnt = preg_match_all('/@\[zrl=(.*?)\](.*?)\[\/zrl\]/ism',$body,$matches,PREG_SET_ORDER); - if($cnt) { - foreach($matches as $mtch) { - // don't include plustags in the term - $term = ((substr($mtch[2],-1,1) === '+') ? substr($mtch[2],0,-1) : $mtch[2]); - $datarray['term'][] = array( - 'uid' => $importer['channel_id'], - 'type' => TERM_MENTION, - 'otype' => TERM_OBJ_POST, - 'term' => $term, - 'url' => $mtch[1] - ); - } - } - - - - - - $newbody = "[share author='" . urlencode($orig_author_name) - . "' profile='" . $orig_author_link - . "' avatar='" . $orig_author_photo - . "' link='" . $orig_url - . "' posted='" . datetime_convert('UTC','UTC',unxmlify($source_xml->post->status_message->created_at)) - . "' message_id='" . unxmlify($source_xml->post->status_message->guid) - . "']" . $body . "[/share]"; - - - $plink = service_plink($contact,$guid); - - $datarray['uid'] = $importer['channel_id']; - $datarray['mid'] = $datarray['parent_mid'] = $guid; - $datarray['changed'] = $datarray['created'] = $datarray['edited'] = datetime_convert('UTC','UTC',$created); - $datarray['item_private'] = $private; - $datarray['plink'] = $plink; - $datarray['owner_xchan'] = $contact['xchan_hash']; - $datarray['author_xchan'] = $contact['xchan_hash']; - - $datarray['body'] = $newbody; - $datarray['app'] = 'Diaspora'; - - - - $tgroup = tgroup_check($importer['channel_id'],$datarray); - - if((! $importer['system']) && (! perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'send_stream')) && (! $tgroup)) { - logger('diaspora_post: Ignoring this author.'); - return 202; - } - - - $result = item_store($datarray); - - return; - -} - - -function diaspora_asphoto($importer,$xml,$msg) { - logger('diaspora_asphoto called'); - - $a = get_app(); - $guid = notags(unxmlify($xml->guid)); - $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); - - if($diaspora_handle != $msg['author']) { - logger('diaspora_post: Potential forgery. Message handle is not the same as envelope sender.'); - return 202; - } - - $contact = diaspora_get_contact_by_handle($importer['channel_id'],$diaspora_handle); - if(! $contact) - return; - - if((! $importer['system']) && (! perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'send_stream'))) { - logger('diaspora_asphoto: Ignoring this author.'); - return 202; - } - - $message_id = $diaspora_handle . ':' . $guid; - $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `guid` = '%s' LIMIT 1", - intval($importer['channel_id']), - dbesc($message_id), - dbesc($guid) - ); - if(count($r)) { - logger('diaspora_asphoto: message exists: ' . $guid); - return; - } - - // allocate a guid on our system - we aren't fixing any collisions. - // we're ignoring them - - $g = q("select * from guid where guid = '%s' limit 1", - dbesc($guid) - ); - if(! count($g)) { - q("insert into guid ( guid ) values ( '%s' )", - dbesc($guid) - ); - } - - $created = unxmlify($xml->created_at); - $private = ((unxmlify($xml->public) == 'false') ? 1 : 0); - - if(strlen($xml->objectId) && ($xml->objectId != 0) && ($xml->image_url)) { - $body = '[url=' . notags(unxmlify($xml->image_url)) . '][img]' . notags(unxmlify($xml->objectId)) . '[/img][/url]' . "\n"; - $body = scale_external_images($body,false); - } - elseif($xml->image_url) { - $body = '[img]' . notags(unxmlify($xml->image_url)) . '[/img]' . "\n"; - $body = scale_external_images($body); - } - else { - logger('diaspora_asphoto: no photo url found.'); - return; - } - - $plink = service_plink($contact,$guid); - - $datarray = array(); - - $datarray['uid'] = $importer['channel_id']; - $datarray['contact-id'] = $contact['id']; - $datarray['wall'] = 0; - $datarray['network'] = NETWORK_DIASPORA; - $datarray['guid'] = $guid; - $datarray['uri'] = $datarray['parent-uri'] = $message_id; - $datarray['changed'] = $datarray['created'] = $datarray['edited'] = datetime_convert('UTC','UTC',$created); - $datarray['private'] = $private; - $datarray['parent'] = 0; - $datarray['plink'] = $plink; - $datarray['owner-name'] = $contact['name']; - $datarray['owner-link'] = $contact['url']; - //$datarray['owner-avatar'] = $contact['thumb']; - $datarray['owner-avatar'] = ((x($contact,'thumb')) ? $contact['thumb'] : $contact['photo']); - $datarray['author-name'] = $contact['name']; - $datarray['author-link'] = $contact['url']; - $datarray['author-avatar'] = $contact['thumb']; - $datarray['body'] = $body; - - $datarray['app'] = 'Diaspora/Cubbi.es'; - - $message_id = item_store($datarray); - - //if($message_id) { - // q("update item set plink = '%s' where id = %d", - // dbesc($a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $message_id), - // intval($message_id) - // ); - //} - - return; - -} - - - - - - -function diaspora_comment($importer,$xml,$msg) { - - $a = get_app(); - $guid = notags(unxmlify($xml->guid)); - $parent_guid = notags(unxmlify($xml->parent_guid)); - $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); - $target_type = notags(unxmlify($xml->target_type)); - $text = unxmlify($xml->text); - $author_signature = notags(unxmlify($xml->author_signature)); - - $parent_author_signature = (($xml->parent_author_signature) ? notags(unxmlify($xml->parent_author_signature)) : ''); - - $contact = diaspora_get_contact_by_handle($importer['channel_id'],$msg['author']); - if(! $contact) { - logger('diaspora_comment: cannot find contact: ' . $msg['author']); - return; - } - - - - $pubcomment = get_pconfig($importer['channel_id'],'system','diaspora_public_comments'); - - // by default comments on public posts are allowed from anybody on Diaspora. That is their policy. - // Once this setting is set to something we'll track your preference and it will over-ride the default. - - if($pubcomment === false) - $pubcomment = 1; - - // Friendica is currently truncating guids at 64 chars - $search_guid = $parent_guid; - if(strlen($parent_guid) == 64) - $search_guid = $parent_guid . '%'; - - $r = q("SELECT * FROM item WHERE uid = %d AND mid LIKE '%s' LIMIT 1", - intval($importer['channel_id']), - dbesc($search_guid) - ); - if(! $r) { - logger('diaspora_comment: parent item not found: parent: ' . $parent_guid . ' item: ' . $guid); - return; - } - - $parent_item = $r[0]; - - if(intval($parent_item['item_private'])) - $pubcomment = 0; - - $search_guid = $guid; - if(strlen($guid) == 64) - $search_guid = $guid . '%'; - - - $r = q("SELECT * FROM item WHERE uid = %d AND mid like '%s' LIMIT 1", - intval($importer['channel_id']), - dbesc($search_guid) - ); - if($r) { - logger('diaspora_comment: our comment just got relayed back to us (or there was a guid collision) : ' . $guid); - return; - } - - - - /* How Diaspora performs comment signature checking: - - - If an item has been sent by the comment author to the top-level post owner to relay on - to the rest of the contacts on the top-level post, the top-level post owner should check - the author_signature, then create a parent_author_signature before relaying the comment on - - If an item has been relayed on by the top-level post owner, the contacts who receive it - check only the parent_author_signature. Basically, they trust that the top-level post - owner has already verified the authenticity of anything he/she sends out - - In either case, the signature that get checked is the signature created by the person - who sent the psuedo-salmon - */ - - $signed_data = $guid . ';' . $parent_guid . ';' . $text . ';' . $diaspora_handle; - $key = $msg['key']; - - if($parent_author_signature) { - // If a parent_author_signature exists, then we've received the comment - // relayed from the top-level post owner. There's no need to check the - // author_signature if the parent_author_signature is valid - - $parent_author_signature = base64_decode($parent_author_signature); - - if(! rsa_verify($signed_data,$parent_author_signature,$key,'sha256')) { - logger('diaspora_comment: top-level owner verification failed.'); - return; - } - } - else { - // If there's no parent_author_signature, then we've received the comment - // from the comment creator. In that case, the person is commenting on - // our post, so he/she must be a contact of ours and his/her public key - // should be in $msg['key'] - - if($importer['system']) { - // don't relay to the sys channel - logger('diaspora_comment: relay to sys channel blocked.'); - return; - } - - $author_signature = base64_decode($author_signature); - - if(! rsa_verify($signed_data,$author_signature,$key,'sha256')) { - logger('diaspora_comment: comment author verification failed.'); - return; - } - } - - // Phew! Everything checks out. Now create an item. - - // Find the original comment author information. - // We need this to make sure we display the comment author - // information (name and avatar) correctly. - - if(strcasecmp($diaspora_handle,$msg['author']) == 0) - $person = $contact; - else { - $person = find_diaspora_person_by_handle($diaspora_handle); - - if(! is_array($person)) { - logger('diaspora_comment: unable to find author details'); - return; - } - } - - - $body = diaspora2bb($text); - - - $maxlen = get_max_import_size(); - - if($maxlen && mb_strlen($body) > $maxlen) { - $body = mb_substr($body,0,$maxlen,'UTF-8'); - logger('message length exceeds max_import_size: truncated'); - } - - - $datarray = array(); - - // Look for tags and linkify them - $results = linkify_tags(get_app(), $body, $importer['channel_id'], true); - - $datarray['term'] = array(); - - if($results) { - foreach($results as $result) { - $success = $result['success']; - if($success['replaced']) { - $datarray['term'][] = array( - 'uid' => $importer['channel_id'], - 'type' => $success['termtype'], - 'otype' => TERM_OBJ_POST, - 'term' => $success['term'], - 'url' => $success['url'] - ); - } - } - } - - $cnt = preg_match_all('/@\[url=(.*?)\](.*?)\[\/url\]/ism',$body,$matches,PREG_SET_ORDER); - if($cnt) { - foreach($matches as $mtch) { - $datarray['term'][] = array( - 'uid' => $importer['channel_id'], - 'type' => TERM_MENTION, - 'otype' => TERM_OBJ_POST, - 'term' => $mtch[2], - 'url' => $mtch[1] - ); - } - } - - $cnt = preg_match_all('/@\[zrl=(.*?)\](.*?)\[\/zrl\]/ism',$body,$matches,PREG_SET_ORDER); - if($cnt) { - foreach($matches as $mtch) { - // don't include plustags in the term - $term = ((substr($mtch[2],-1,1) === '+') ? substr($mtch[2],0,-1) : $mtch[2]); - $datarray['term'][] = array( - 'uid' => $importer['channel_id'], - 'type' => TERM_MENTION, - 'otype' => TERM_OBJ_POST, - 'term' => $term, - 'url' => $mtch[1] - ); - } - } - - $datarray['uid'] = $importer['channel_id']; - $datarray['verb'] = ACTIVITY_POST; - $datarray['mid'] = $guid; - $datarray['parent_mid'] = $parent_item['mid']; - - // set the route to that of the parent so downstream hubs won't reject it. - $datarray['route'] = $parent_item['route']; - - // No timestamps for comments? OK, we'll the use current time. - $datarray['changed'] = $datarray['created'] = $datarray['edited'] = datetime_convert(); - $datarray['item_private'] = $parent_item['item_private']; - - $datarray['owner_xchan'] = $parent_item['owner_xchan']; - $datarray['author_xchan'] = $person['xchan_hash']; - - $datarray['body'] = $body; - - if(strstr($person['xchan_network'],'friendica')) - $app = 'Friendica'; - else - $app = 'Diaspora'; - - $datarray['app'] = $app; - - if(! $parent_author_signature) { - $key = get_config('system','pubkey'); - $x = array('signer' => $diaspora_handle, 'body' => $text, - 'signed_text' => $signed_data, 'signature' => base64_encode($author_signature)); - $datarray['diaspora_meta'] = json_encode(crypto_encapsulate(json_encode($x),$key)); - } - - - - // So basically if something arrives at the sys channel it's by definition public and we allow it. - // If $pubcomment and the parent was public, we allow it. - // In all other cases, honour the permissions for this Diaspora connection - - $tgroup = tgroup_check($importer['channel_id'],$datarray); - - if((! $importer['system']) && (! $pubcomment) && (! perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'post_comments')) && (! $tgroup)) { - logger('diaspora_comment: Ignoring this author.'); - return 202; - } - - - - - $result = item_store($datarray); - - if($result && $result['success']) - $message_id = $result['item_id']; - - if(($parent_item['item_flags'] & ITEM_ORIGIN) && (! $parent_author_signature)) { - // if the message isn't already being relayed, notify others - // the existence of parent_author_signature means the parent_author or owner - // is already relaying. - - proc_run('php','include/notifier.php','comment-import',$message_id); - } - - if($result['item_id']) { - $r = q("select * from item where id = %d limit 1", - intval($result['item_id']) - ); - if($r) - send_status_notifications($result['item_id'],$r[0]); - } - - return; -} - - - - -function diaspora_conversation($importer,$xml,$msg) { - - $a = get_app(); - - $guid = notags(unxmlify($xml->guid)); - $subject = notags(unxmlify($xml->subject)); - $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); - $participant_handles = notags(unxmlify($xml->participant_handles)); - $created_at = datetime_convert('UTC','UTC',notags(unxmlify($xml->created_at))); - - $parent_uri = $diaspora_handle . ':' . $guid; - - $messages = $xml->message; - - if(! count($messages)) { - logger('diaspora_conversation: empty conversation'); - return; - } - - $contact = diaspora_get_contact_by_handle($importer['channel_id'],$msg['author']); - if(! $contact) { - logger('diaspora_conversation: cannot find contact: ' . $msg['author']); - return; - } - - - if(! perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'post_mail')) { - logger('diaspora_conversation: Ignoring this author.'); - return 202; - } - - $conversation = null; - - $c = q("select * from conv where uid = %d and guid = '%s' limit 1", - intval($importer['channel_id']), - dbesc($guid) - ); - if(count($c)) - $conversation = $c[0]; - else { - $r = q("insert into conv (uid,guid,creator,created,updated,subject,recips) values(%d, '%s', '%s', '%s', '%s', '%s', '%s') ", - intval($importer['channel_id']), - dbesc($guid), - dbesc($diaspora_handle), - dbesc(datetime_convert('UTC','UTC',$created_at)), - dbesc(datetime_convert()), - dbesc($subject), - dbesc($participant_handles) - ); - if($r) - $c = q("select * from conv where uid = %d and guid = '%s' limit 1", - intval($importer['channel_id']), - dbesc($guid) - ); - if(count($c)) - $conversation = $c[0]; - } - if(! $conversation) { - logger('diaspora_conversation: unable to create conversation.'); - return; - } - - foreach($messages as $mesg) { - - $reply = 0; - - $msg_guid = notags(unxmlify($mesg->guid)); - $msg_parent_guid = notags(unxmlify($mesg->parent_guid)); - $msg_parent_author_signature = notags(unxmlify($mesg->parent_author_signature)); - $msg_author_signature = notags(unxmlify($mesg->author_signature)); - $msg_text = unxmlify($mesg->text); - $msg_created_at = datetime_convert('UTC','UTC',notags(unxmlify($mesg->created_at))); - $msg_diaspora_handle = notags(unxmlify($mesg->diaspora_handle)); - $msg_conversation_guid = notags(unxmlify($mesg->conversation_guid)); - if($msg_conversation_guid != $guid) { - logger('diaspora_conversation: message conversation guid does not belong to the current conversation. ' . $xml); - continue; - } - - $body = diaspora2bb($msg_text); - - - $maxlen = get_max_import_size(); - - if($maxlen && mb_strlen($body) > $maxlen) { - $body = mb_substr($body,0,$maxlen,'UTF-8'); - logger('message length exceeds max_import_size: truncated'); - } - - - $author_signed_data = $msg_guid . ';' . $msg_parent_guid . ';' . $msg_text . ';' . unxmlify($mesg->created_at) . ';' . $msg_diaspora_handle . ';' . $msg_conversation_guid; - - $author_signature = base64_decode($msg_author_signature); - - if(strcasecmp($msg_diaspora_handle,$msg['author']) == 0) { - $person = $contact; - $key = $msg['key']; - } - else { - $person = find_diaspora_person_by_handle($msg_diaspora_handle); - - if(is_array($person) && x($person,'xchan_pubkey')) - $key = $person['xchan_pubkey']; - else { - logger('diaspora_conversation: unable to find author details'); - continue; - } - } - - if(! rsa_verify($author_signed_data,$author_signature,$key,'sha256')) { - logger('diaspora_conversation: verification failed.'); - continue; - } - - if($msg_parent_author_signature) { - $owner_signed_data = $msg_guid . ';' . $msg_parent_guid . ';' . $msg_text . ';' . unxmlify($mesg->created_at) . ';' . $msg_diaspora_handle . ';' . $msg_conversation_guid; - - $parent_author_signature = base64_decode($msg_parent_author_signature); - - $key = $msg['key']; - - if(! rsa_verify($owner_signed_data,$parent_author_signature,$key,'sha256')) { - logger('diaspora_conversation: owner verification failed.'); - continue; - } - } - - $r = q("select id from mail where mid = '%s' limit 1", - dbesc($message_id) - ); - if(count($r)) { - logger('diaspora_conversation: duplicate message already delivered.', LOGGER_DEBUG); - continue; - } - - $key = get_config('system','pubkey'); - if($subject) - $subject = json_encode(crypto_encapsulate($subject,$key)); - if($body) - $body = json_encode(crypto_encapsulate($body,$key)); - - q("insert into mail ( `channel_id`, `convid`, `from_xchan`,`to_xchan`,`title`,`body`,`mail_flags`,`mid`,`parent_mid`,`created`) values ( %d, %d, '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s')", - intval($importer['channel_id']), - intval($conversation['id']), - dbesc($person['xchan_hash']), - dbesc($importer['channel_hash']), - dbesc($subject), - dbesc($body), - intval(MAIL_OBSCURED), - dbesc($msg_guid), - dbesc($parent_uri), - dbesc($msg_created_at) - ); - - q("update conv set updated = '%s' where id = %d", - dbesc(datetime_convert()), - intval($conversation['id']) - ); - - require_once('include/enotify.php'); -/****** -//FIXME - - notification(array( - 'type' => NOTIFY_MAIL, - 'notify_flags' => $importer['notify-flags'], - 'language' => $importer['language'], - 'to_name' => $importer['username'], - 'to_email' => $importer['email'], - 'uid' =>$importer['importer_uid'], - 'item' => array('subject' => $subject, 'body' => $body), - 'source_name' => $person['name'], - 'source_link' => $person['url'], - 'source_photo' => $person['thumb'], - 'verb' => ACTIVITY_POST, - 'otype' => 'mail' - )); -*******/ - - } - - return; -} - -function diaspora_message($importer,$xml,$msg) { - - $a = get_app(); - - $msg_guid = notags(unxmlify($xml->guid)); - $msg_parent_guid = notags(unxmlify($xml->parent_guid)); - $msg_parent_author_signature = notags(unxmlify($xml->parent_author_signature)); - $msg_author_signature = notags(unxmlify($xml->author_signature)); - $msg_text = unxmlify($xml->text); - $msg_created_at = datetime_convert('UTC','UTC',notags(unxmlify($xml->created_at))); - $msg_diaspora_handle = notags(unxmlify($xml->diaspora_handle)); - $msg_conversation_guid = notags(unxmlify($xml->conversation_guid)); - - $parent_uri = $msg_parent_guid; - - $contact = diaspora_get_contact_by_handle($importer['channel_id'],$msg_diaspora_handle); - if(! $contact) { - logger('diaspora_message: cannot find contact: ' . $msg_diaspora_handle); - return; - } - - if(($contact['rel'] == CONTACT_IS_FOLLOWER) || ($contact['blocked']) || ($contact['readonly'])) { - logger('diaspora_message: Ignoring this author.'); - return 202; - } - - $conversation = null; - - $c = q("select * from conv where uid = %d and guid = '%s' limit 1", - intval($importer['channel_id']), - dbesc($msg_conversation_guid) - ); - if($c) - $conversation = $c[0]; - else { - logger('diaspora_message: conversation not available.'); - return; - } - - $reply = 0; - - $subject = $conversation['subject']; - $body = diaspora2bb($msg_text); - - - $maxlen = get_max_import_size(); - - if($maxlen && mb_strlen($body) > $maxlen) { - $body = mb_substr($body,0,$maxlen,'UTF-8'); - logger('message length exceeds max_import_size: truncated'); - } - - - - $message_id = $msg_diaspora_handle . ':' . $msg_guid; - - $author_signed_data = $msg_guid . ';' . $msg_parent_guid . ';' . $msg_text . ';' . unxmlify($xml->created_at) . ';' . $msg_diaspora_handle . ';' . $msg_conversation_guid; - - - $author_signature = base64_decode($msg_author_signature); - - $person = find_diaspora_person_by_handle($msg_diaspora_handle); - if(is_array($person) && x($person,'xchan_pubkey')) - $key = $person['xchan_pubkey']; - else { - logger('diaspora_message: unable to find author details'); - return; - } - - if(! rsa_verify($author_signed_data,$author_signature,$key,'sha256')) { - logger('diaspora_message: verification failed.'); - return; - } - - $r = q("select id from mail where mid = '%s' and channel_id = %d limit 1", - dbesc($message_id), - intval($importer['channel_id']) - ); - if($r) { - logger('diaspora_message: duplicate message already delivered.', LOGGER_DEBUG); - return; - } - - $key = get_config('system','pubkey'); - if($subject) - $subject = json_encode(crypto_encapsulate($subject,$key)); - if($body) - $body = json_encode(crypto_encapsulate($body,$key)); - - q("insert into mail ( `channel_id`, `convid`, `from_xchan`,`to_xchan`,`title`,`body`,`mail_flags`,`mid`,`parent_mid`,`created`) values ( %d, %d, '%s', '%s', '%s', '%s', '%d','%s','%s','%s')", - intval($importer['channel_id']), - intval($conversation['id']), - dbesc($person['xchan_hash']), - dbesc($importer['xchan_hash']), - dbesc($subject), - dbesc($body), - intval(MAIL_OBSCURED), - dbesc($msg_guid), - dbesc($parent_uri), - dbesc($msg_created_at) - ); - - q("update conv set updated = '%s' where id = %d", - dbesc(datetime_convert()), - intval($conversation['id']) - ); - - return; -} - - -function diaspora_photo($importer,$xml,$msg) { - - $a = get_app(); - - logger('diaspora_photo: init',LOGGER_DEBUG); - - $remote_photo_path = notags(unxmlify($xml->remote_photo_path)); - - $remote_photo_name = notags(unxmlify($xml->remote_photo_name)); - - $status_message_guid = notags(unxmlify($xml->status_message_guid)); - - $guid = notags(unxmlify($xml->guid)); - - $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); - - $public = notags(unxmlify($xml->public)); - - $created_at = notags(unxmlify($xml_created_at)); - - logger('diaspora_photo: status_message_guid: ' . $status_message_guid, LOGGER_DEBUG); - - $contact = diaspora_get_contact_by_handle($importer['channel_id'],$msg['author']); - if(! $contact) { - logger('diaspora_photo: contact record not found: ' . $msg['author'] . ' handle: ' . $diaspora_handle); - return; - } - - if((! $importer['system']) && (! perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'send_stream'))) { - logger('diaspora_photo: Ignoring this author.'); - return 202; - } - - $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `mid` = '%s' LIMIT 1", - intval($importer['channel_id']), - dbesc($status_message_guid) - ); - if(! $r) { - logger('diaspora_photo: attempt = ' . $attempt . '; status message not found: ' . $status_message_guid . ' for photo: ' . $guid); - return; - } - -// $parent_item = $r[0]; - -// $link_text = '[img]' . $remote_photo_path . $remote_photo_name . '[/img]' . "\n"; - -// $link_text = scale_external_images($link_text, true, -// array($remote_photo_name, 'scaled_full_' . $remote_photo_name)); - -// if(strpos($parent_item['body'],$link_text) === false) { -// $r = q("update item set `body` = '%s', `visible` = 1 where `id` = %d and `uid` = %d", -// dbesc($link_text . $parent_item['body']), -// intval($parent_item['id']), -// intval($parent_item['uid']) -// ); -// } - - return; -} - - - - -function diaspora_like($importer,$xml,$msg) { - - $a = get_app(); - $guid = notags(unxmlify($xml->guid)); - $parent_guid = notags(unxmlify($xml->parent_guid)); - $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); - $target_type = notags(unxmlify($xml->target_type)); - $positive = notags(unxmlify($xml->positive)); - $author_signature = notags(unxmlify($xml->author_signature)); - - $parent_author_signature = (($xml->parent_author_signature) ? notags(unxmlify($xml->parent_author_signature)) : ''); - - // likes on comments not supported here and likes on photos not supported by Diaspora - -// if($target_type !== 'Post') -// return; - - $contact = diaspora_get_contact_by_handle($importer['channel_id'],$msg['author']); - if(! $contact) { - logger('diaspora_like: cannot find contact: ' . $msg['author'] . ' for channel ' . $importer['channel_name']); - return; - } - - - if((! $importer['system']) && (! perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'post_comments'))) { - logger('diaspora_like: Ignoring this author.'); - return 202; - } - - $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `mid` = '%s' LIMIT 1", - intval($importer['channel_id']), - dbesc($parent_guid) - ); - if(! count($r)) { - logger('diaspora_like: parent item not found: ' . $guid); - return; - } - - $parent_item = $r[0]; - - $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `mid` = '%s' LIMIT 1", - intval($importer['channel_id']), - dbesc($guid) - ); - if(count($r)) { - if($positive === 'true') { - logger('diaspora_like: duplicate like: ' . $guid); - return; - } - // Note: I don't think "Like" objects with positive = "false" are ever actually used - // It looks like "RelayableRetractions" are used for "unlike" instead - if($positive === 'false') { - logger('diaspora_like: received a like with positive set to "false"...ignoring'); - // perhaps call drop_item() - // FIXME--actually don't unless it turns out that Diaspora does indeed send out "false" likes - // send notification via proc_run() - return; - } - } - - $i = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($parent_item['author_xchan']) - ); - if($i) - $item_author = $i[0]; - - // Note: I don't think "Like" objects with positive = "false" are ever actually used - // It looks like "RelayableRetractions" are used for "unlike" instead - if($positive === 'false') { - logger('diaspora_like: received a like with positive set to "false"'); - logger('diaspora_like: unlike received with no corresponding like...ignoring'); - return; - } - - - /* How Diaspora performs "like" signature checking: - - - If an item has been sent by the like author to the top-level post owner to relay on - to the rest of the contacts on the top-level post, the top-level post owner should check - the author_signature, then create a parent_author_signature before relaying the like on - - If an item has been relayed on by the top-level post owner, the contacts who receive it - check only the parent_author_signature. Basically, they trust that the top-level post - owner has already verified the authenticity of anything he/she sends out - - In either case, the signature that get checked is the signature created by the person - who sent the salmon - */ - - // 2014-09-10 let's try this: signatures are failing. I'll try and make a signable string from - // the parameters in the order they were presented in the post. This is how D* creates the signable string. - - - $signed_data = $positive . ';' . $guid . ';' . $target_type . ';' . $parent_guid . ';' . $diaspora_handle; - - $key = $msg['key']; - - if($parent_author_signature) { - // If a parent_author_signature exists, then we've received the like - // relayed from the top-level post owner. There's no need to check the - // author_signature if the parent_author_signature is valid - - $parent_author_signature = base64_decode($parent_author_signature); - - if(! rsa_verify($signed_data,$parent_author_signature,$key,'sha256')) { - if (intval(get_config('system','ignore_diaspora_like_signature'))) - logger('diaspora_like: top-level owner verification failed. Proceeding anyway.'); - else { - logger('diaspora_like: top-level owner verification failed.'); - return; - } - } - } - else { - // If there's no parent_author_signature, then we've received the like - // from the like creator. In that case, the person is "like"ing - // our post, so he/she must be a contact of ours and his/her public key - // should be in $msg['key'] - - $author_signature = base64_decode($author_signature); - - if(! rsa_verify($signed_data,$author_signature,$key,'sha256')) { - if (intval(get_config('system','ignore_diaspora_like_signature'))) - logger('diaspora_like: like creator verification failed. Proceeding anyway'); - else { - logger('diaspora_like: like creator verification failed.'); - return; - } - } - } - - logger('diaspora_like: signature check complete.',LOGGER_DEBUG); - - // Phew! Everything checks out. Now create an item. - - // Find the original comment author information. - // We need this to make sure we display the comment author - // information (name and avatar) correctly. - if(strcasecmp($diaspora_handle,$msg['author']) == 0) - $person = $contact; - else { - $person = find_diaspora_person_by_handle($diaspora_handle); - - if(! is_array($person)) { - logger('diaspora_like: unable to find author details'); - return; - } - } - - $uri = $diaspora_handle . ':' . $guid; - - $activity = ACTIVITY_LIKE; - - $post_type = (($parent_item['resource_type'] === 'photo') ? t('photo') : t('status')); - - $links = array(array('rel' => 'alternate','type' => 'text/html', 'href' => $parent_item['plink'])); - $objtype = (($parent_item['resource_type'] === 'photo') ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE ); - - $body = $parent_item['body']; - - - $object = json_encode(array( - 'type' => $post_type, - 'id' => $parent_item['mid'], - 'parent' => (($parent_item['thr_parent']) ? $parent_item['thr_parent'] : $parent_item['parent_mid']), - 'link' => $links, - 'title' => $parent_item['title'], - 'content' => $parent_item['body'], - 'created' => $parent_item['created'], - 'edited' => $parent_item['edited'], - 'author' => array( - 'name' => $item_author['xchan_name'], - 'address' => $item_author['xchan_addr'], - 'guid' => $item_author['xchan_guid'], - 'guid_sig' => $item_author['xchan_guid_sig'], - 'link' => array( - array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item_author['xchan_url']), - array('rel' => 'photo', 'type' => $item_author['xchan_photo_mimetype'], 'href' => $item_author['xchan_photo_m'])), - ), - )); - - - $bodyverb = t('%1$s likes %2$s\'s %3$s'); - - $arr = array(); - - $arr['uid'] = $importer['channel_id']; - $arr['aid'] = $importer['channel_account_id']; - $arr['mid'] = $guid; - $arr['parent_mid'] = $parent_item['mid']; - $arr['owner_xchan'] = $parent_item['owner_xchan']; - $arr['author_xchan'] = $person['xchan_hash']; - - $ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]'; - $alink = '[url=' . $parent_item['author-link'] . ']' . $parent_item['author-name'] . '[/url]'; - $plink = '[url='. z_root() .'/display/'.$guid.']'.$post_type.'[/url]'; - $arr['body'] = sprintf( $bodyverb, $ulink, $alink, $plink ); - - $arr['app'] = 'Diaspora'; - - // set the route to that of the parent so downstream hubs won't reject it. - $arr['route'] = $parent_item['route']; - - $arr['item_private'] = $parent_item['item_private']; - $arr['verb'] = $activity; - $arr['obj_type'] = $objtype; - $arr['object'] = $object; - - if(! $parent_author_signature) { - $key = get_config('system','pubkey'); - $x = array('signer' => $diaspora_handle, 'body' => $text, - 'signed_text' => $signed_data, 'signature' => base64_encode($author_signature)); - $arr['diaspora_meta'] = json_encode(crypto_encapsulate(json_encode($x),$key)); - } - - $x = item_store($arr); - - if($x) - $message_id = $x['item_id']; - - // if the message isn't already being relayed, notify others - // the existence of parent_author_signature means the parent_author or owner - // is already relaying. The parent_item['origin'] indicates the message was created on our system - - if(($parent_item['item_flags'] & ITEM_ORIGIN) && (! $parent_author_signature)) - proc_run('php','include/notifier.php','comment-import',$message_id); - - return; -} - -function diaspora_retraction($importer,$xml) { - - - $guid = notags(unxmlify($xml->guid)); - $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); - $type = notags(unxmlify($xml->type)); - - $contact = diaspora_get_contact_by_handle($importer['channel_id'],$diaspora_handle); - if(! $contact) - return; - - if($type === 'Person') { - require_once('include/Contact.php'); - contact_remove($importer['channel_id'],$contact['abook_id']); - } - elseif($type === 'Post') { - $r = q("select * from item where mid = '%s' and uid = %d limit 1", - dbesc('guid'), - intval($importer['channel_id']) - ); - if(count($r)) { - if(link_compare($r[0]['author_xchan'],$contact['xchan_hash'])) { - drop_item($r[0]['id'],false); - } - } - } - - return 202; - // NOTREACHED -} - -function diaspora_signed_retraction($importer,$xml,$msg) { - - - $guid = notags(unxmlify($xml->target_guid)); - $diaspora_handle = notags(unxmlify($xml->sender_handle)); - $type = notags(unxmlify($xml->target_type)); - $sig = notags(unxmlify($xml->target_author_signature)); - - $parent_author_signature = (($xml->parent_author_signature) ? notags(unxmlify($xml->parent_author_signature)) : ''); - - $contact = diaspora_get_contact_by_handle($importer['channel_id'],$diaspora_handle); - if(! $contact) { - logger('diaspora_signed_retraction: no contact ' . $diaspora_handle . ' for ' . $importer['channel_id']); - return; - } - - - $signed_data = $guid . ';' . $type ; - $key = $msg['key']; - - /* How Diaspora performs relayable_retraction signature checking: - - - If an item has been sent by the item author to the top-level post owner to relay on - to the rest of the contacts on the top-level post, the top-level post owner checks - the author_signature, then creates a parent_author_signature before relaying the item on - - If an item has been relayed on by the top-level post owner, the contacts who receive it - check only the parent_author_signature. Basically, they trust that the top-level post - owner has already verified the authenticity of anything he/she sends out - - In either case, the signature that get checked is the signature created by the person - who sent the salmon - */ - - if($parent_author_signature) { - - $parent_author_signature = base64_decode($parent_author_signature); - - if(! rsa_verify($signed_data,$parent_author_signature,$key,'sha256')) { - logger('diaspora_signed_retraction: top-level post owner verification failed'); - return; - } - - } - else { - - $sig_decode = base64_decode($sig); - - if(! rsa_verify($signed_data,$sig_decode,$key,'sha256')) { - logger('diaspora_signed_retraction: retraction owner verification failed.' . print_r($msg,true)); - return; - } - } - - if($type === 'StatusMessage' || $type === 'Comment' || $type === 'Like') { - $r = q("select * from item where mid = '%s' and uid = %d limit 1", - dbesc($guid), - intval($importer['channel_id']) - ); - if($r) { - if($r[0]['author_xchan'] == $contact['xchan_hash']) { - - drop_item($r[0]['id'],false, DROPITEM_PHASE1); - - // Now check if the retraction needs to be relayed by us - // - // The first item in the `item` table with the parent id is the parent. However, MySQL doesn't always - // return the items ordered by `item`.`id`, in which case the wrong item is chosen as the parent. - // The only item with `parent` and `id` as the parent id is the parent item. - $p = q("select item_flags from item where parent = %d and id = %d limit 1", - $r[0]['parent'], - $r[0]['parent'] - ); - if($p) { - if(($p[0]['item_flags'] & ITEM_ORIGIN) && (! $parent_author_signature)) { -// FIXME so we can relay this -// q("insert into sign (`retract_iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", -// $r[0]['id'], -// dbesc($signed_data), -// dbesc($sig), -// dbesc($diaspora_handle) -// ); - - // the existence of parent_author_signature would have meant the parent_author or owner - // is already relaying. - logger('diaspora_signed_retraction: relaying relayable_retraction'); - - proc_run('php','include/notifier.php','drop',$r[0]['id']); - } - } - } - } - } - else - logger('diaspora_signed_retraction: unknown type: ' . $type); - - return 202; - // NOTREACHED -} - -function diaspora_profile($importer,$xml,$msg) { - - $a = get_app(); - $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); - - - if($diaspora_handle != $msg['author']) { - logger('diaspora_post: Potential forgery. Message handle is not the same as envelope sender.'); - return 202; - } - - $contact = diaspora_get_contact_by_handle($importer['channel_id'],$diaspora_handle); - if(! $contact) - return; - - if($contact['blocked']) { - logger('diaspora_post: Ignoring this author.'); - return 202; - } - - $name = unxmlify($xml->first_name) . ((strlen($xml->last_name)) ? ' ' . unxmlify($xml->last_name) : ''); - $image_url = unxmlify($xml->image_url); - $birthday = unxmlify($xml->birthday); - - - $handle_parts = explode("@", $diaspora_handle); - if($name === '') { - $name = $handle_parts[0]; - } - - if( preg_match("|^https?://|", $image_url) === 0) { - $image_url = "http://" . $handle_parts[1] . $image_url; - } - - require_once('include/photo/photo_driver.php'); - - $images = import_profile_photo($image_url,$contact['xchan_hash']); - - // Generic birthday. We don't know the timezone. The year is irrelevant. - - $birthday = str_replace('1000','1901',$birthday); - - $birthday = datetime_convert('UTC','UTC',$birthday,'Y-m-d'); - - // this is to prevent multiple birthday notifications in a single year - // if we already have a stored birthday and the 'm-d' part hasn't changed, preserve the entry, which will preserve the notify year - - if(substr($birthday,5) === substr($contact['bd'],5)) - $birthday = $contact['bd']; - - $r = q("update xchan set xchan_name = '%s', xchan_name_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s' ", - dbesc($name), - dbesc(datetime_convert()), - dbesc($images[0]), - dbesc($images[1]), - dbesc($images[2]), - dbesc($images[3]), - dbesc(datetime_convert()), - intval($contact['xchan_hash']) - ); - - return; - -} - -function diaspora_share($owner,$contact) { - $a = get_app(); - - $enabled = intval(get_config('system','diaspora_enabled')); - if(! $enabled) { - logger('diaspora_share: disabled'); - return; - } - - $allowed = get_pconfig($owner['channel_id'],'system','diaspora_allowed'); - if($allowed === false) - $allowed = 1; - - if(! intval($allowed)) { - logger('diaspora_share: disallowed for channel ' . $importer['channel_name']); - return; - } - - - - $myaddr = $owner['channel_address'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3); - - if(! array_key_exists('xchan_hash',$contact)) { - $c = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where xchan_hash = '%s' limit 1", - dbesc($contact['hubloc_hash']) - ); - if(! $c) { - logger('diaspora_share: ' . $contact['hubloc_hash'] . ' not found.'); - return; - } - $contact = $c[0]; - } - - $theiraddr = $contact['xchan_addr']; - - $tpl = get_markup_template('diaspora_share.tpl'); - $msg = replace_macros($tpl, array( - '$sender' => $myaddr, - '$recipient' => $theiraddr - )); - - $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['channel_prvkey'],$contact['xchan_pubkey']))); - return(diaspora_transmit($owner,$contact,$slap, false)); -} - -function diaspora_unshare($owner,$contact) { - - $a = get_app(); - $myaddr = $owner['channel_address'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3); - - $tpl = get_markup_template('diaspora_retract.tpl'); - $msg = replace_macros($tpl, array( - '$guid' => $owner['channel_guid'], - '$type' => 'Person', - '$handle' => $myaddr - )); - - $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['channel_prvkey'],$contact['xchan_pubkey']))); - - return(diaspora_transmit($owner,$contact,$slap, false)); -} - - -function diaspora_send_status($item,$owner,$contact,$public_batch = false) { - - $a = get_app(); - $myaddr = $owner['channel_address'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3); - - if(intval($item['id']) != intval($item['parent'])) { - logger('attempted to send a comment as a top-level post'); - return; - } - - $images = array(); - - $title = $item['title']; - $body = bb2diaspora_itembody($item,true); - -/* - // We're trying to match Diaspora's split message/photo protocol but - // all the photos are displayed on D* as links and not img's - even - // though we're sending pretty much precisely what they send us when - // doing the same operation. - // Commented out for now, we'll use bb2diaspora to convert photos to markdown - // which seems to get through intact. - - $cnt = preg_match_all('|\[img\](.*?)\[\/img\]|',$body,$matches,PREG_SET_ORDER); - if($cnt) { - foreach($matches as $mtch) { - $detail = array(); - $detail['str'] = $mtch[0]; - $detail['path'] = dirname($mtch[1]) . '/'; - $detail['file'] = basename($mtch[1]); - $detail['guid'] = $item['guid']; - $detail['handle'] = $myaddr; - $images[] = $detail; - $body = str_replace($detail['str'],$mtch[1],$body); - } - } -*/ - - if($item['item_flags'] & ITEM_CONSENSUS) { - $poll = replace_macros(get_markup_template('diaspora_consensus.tpl'), array( - '$guid_q' => random_string(), - '$question' => t('Please choose'), - '$guid_y' => random_string(), - '$agree' => t('Agree'), - '$guid_n' => random_string(), - '$disagree' => t('Disagree'), - '$guid_a' => random_string(), - '$abstain' => t('Abstain') - )); - } - else - $poll = ''; - - $public = (($item['item_private']) ? 'false' : 'true'); - - require_once('include/datetime.php'); - $created = datetime_convert('UTC','UTC',$item['created'],'Y-m-d H:i:s \U\T\C'); - - // Detect a share element and do a reshare - // see: https://github.com/Raven24/diaspora-federation/blob/master/lib/diaspora-federation/entities/reshare.rb - if (!$item['item_private'] AND ($ret = diaspora_is_reshare($item["body"]))) { - $tpl = get_markup_template('diaspora_reshare.tpl'); - $msg = replace_macros($tpl, array( - '$root_handle' => xmlify($ret['root_handle']), - '$root_guid' => $ret['root_guid'], - '$guid' => $item['mid'], - '$handle' => xmlify($myaddr), - '$public' => $public, - '$created' => $created, - '$provider' => (($item['app']) ? $item['app'] : t('$projectname')) - )); - } else { - $tpl = get_markup_template('diaspora_post.tpl'); - $msg = replace_macros($tpl, array( - '$body' => xmlify($body), - '$guid' => $item['mid'], - '$poll' => $poll, - '$handle' => xmlify($myaddr), - '$public' => $public, - '$created' => $created, - '$provider' => (($item['app']) ? $item['app'] : t('$projectname')) - )); - } - - logger('diaspora_send_status: '.$owner['channel_name'].' -> '.$contact['xchan_name'].' base message: ' . $msg, LOGGER_DATA); - - $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['channel_prvkey'],$contact['xchan_pubkey'],$public_batch))); - - $return_code = diaspora_transmit($owner,$contact,$slap,$public_batch); - -// logger('diaspora_send_status: guid: '.$item['mid'].' result '.$return_code, LOGGER_DEBUG); - - if(count($images)) { - diaspora_send_images($item,$owner,$contact,$images,$public_batch); - } - - return $return_code; -} - -function diaspora_is_reshare($body) { - - $body = trim($body); - - // Skip if it isn't a pure repeated messages - // Does it start with a share? - if(strpos($body, "[share") > 0) - return(false); - - // Does it end with a share? - if(strlen($body) > (strrpos($body, "[/share]") + 8)) - return(false); - - $attributes = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","$1",$body); - // Skip if there is no shared message in there - if ($body == $attributes) - return(false); - - $profile = ""; - preg_match("/profile='(.*?)'/ism", $attributes, $matches); - if ($matches[1] != "") - $profile = $matches[1]; - - preg_match('/profile="(.*?)"/ism', $attributes, $matches); - if ($matches[1] != "") - $profile = $matches[1]; - - $ret= array(); - - $ret["root_handle"] = preg_replace("=https?://(.*)/u/(.*)=ism", "$2@$1", $profile); - if (($ret["root_handle"] == $profile) OR ($ret["root_handle"] == "")) - return(false); - - $link = ""; - preg_match("/link='(.*?)'/ism", $attributes, $matches); - if ($matches[1] != "") - $link = $matches[1]; - - preg_match('/link="(.*?)"/ism', $attributes, $matches); - if ($matches[1] != "") - $link = $matches[1]; - - $ret["root_guid"] = preg_replace("=https?://(.*)/posts/(.*)=ism", "$2", $link); - if (($ret["root_guid"] == $link) OR ($ret["root_guid"] == "")) - return(false); - - return($ret); -} - -function diaspora_send_images($item,$owner,$contact,$images,$public_batch = false) { - $a = get_app(); - if(! count($images)) - return; - $mysite = substr($a->get_baseurl(),strpos($a->get_baseurl(),'://') + 3) . '/photo'; - - $tpl = get_markup_template('diaspora_photo.tpl'); - foreach($images as $image) { - if(! stristr($image['path'],$mysite)) - continue; - $resource = str_replace('.jpg','',$image['file']); - $resource = substr($resource,0,strpos($resource,'-')); - - $r = q("select * from photo where `resource_id` = '%s' and `uid` = %d limit 1", - dbesc($resource), - intval($owner['uid']) - ); - if(! $r) - continue; - $public = (($r[0]['allow_cid'] || $r[0]['allow_gid'] || $r[0]['deny_cid'] || $r[0]['deny_gid']) ? 'false' : 'true' ); - $msg = replace_macros($tpl,array( - '$path' => xmlify($image['path']), - '$filename' => xmlify($image['file']), - '$msg_guid' => xmlify($image['guid']), - '$guid' => xmlify($r[0]['resource_id']), - '$handle' => xmlify($image['handle']), - '$public' => xmlify($public), - '$created_at' => xmlify(datetime_convert('UTC','UTC',$r[0]['created'],'Y-m-d H:i:s \U\T\C')) - )); - - - logger('diaspora_send_photo: base message: ' . $msg, LOGGER_DATA); - $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['channel_prvkey'],$contact['xchan_pubkey'],$public_batch))); - - diaspora_transmit($owner,$contact,$slap,$public_batch); - } - -} - -function diaspora_send_followup($item,$owner,$contact,$public_batch = false) { - - $a = get_app(); - $myaddr = $owner['channel_address'] . '@' . get_app()->get_hostname(); - $theiraddr = $contact['xchan_addr']; - - // Diaspora doesn't support threaded comments, but some - // versions of Diaspora (i.e. Diaspora-pistos) support - // likes on comments - if(($item['verb'] === ACTIVITY_LIKE || $item['verb'] === ACTIVITY_DISLIKE) && $item['thr_parent']) { - $p = q("select mid, parent_mid from item where mid = '%s' limit 1", - dbesc($item['thr_parent']) - ); - } - else { - // The first item in the `item` table with the parent id is the parent. However, MySQL doesn't always - // return the items ordered by `item`.`id`, in which case the wrong item is chosen as the parent. - // The only item with `parent` and `id` as the parent id is the parent item. - $p = q("select * from item where parent = %d and id = %d limit 1", - intval($item['parent']), - intval($item['parent']) - ); - } - if($p) - $parent = $p[0]; - else - return; - - - if(($item['verb'] === ACTIVITY_LIKE) && ($parent['mid'] === $parent['parent_mid'])) { - $tpl = get_markup_template('diaspora_like.tpl'); - $like = true; - $target_type = 'Post'; - $positive = 'true'; - - if(($item_['item_restrict'] & ITEM_DELETED)) - logger('diaspora_send_followup: received deleted "like". Those should go to diaspora_send_retraction'); - } - else { - $tpl = get_markup_template('diaspora_comment.tpl'); - $like = false; - } - - if($item['diaspora_meta'] && ! $like) { - $diaspora_meta = json_decode($item['diaspora_meta'],true); - if($diaspora_meta) { - if(array_key_exists('iv',$diaspora_meta)) { - $key = get_config('system','prvkey'); - $meta = json_decode(crypto_unencapsulate($diaspora_meta,$key),true); - } - else - $meta = $diaspora_meta; - } - $signed_text = $meta['signed_text']; - $authorsig = $meta['signature']; - $signer = $meta['signer']; - $text = $meta['body']; - } - else { - $text = bb2diaspora_itembody($item); - - // sign it - - if($like) - $signed_text = $item['mid'] . ';' . $target_type . ';' . $parent['mid'] . ';' . $positive . ';' . $myaddr; - else - $signed_text = $item['mid'] . ';' . $parent['mid'] . ';' . $text . ';' . $myaddr; - - $authorsig = base64_encode(rsa_sign($signed_text,$owner['channel_prvkey'],'sha256')); - - } - - $msg = replace_macros($tpl,array( - '$guid' => xmlify($item['mid']), - '$parent_guid' => xmlify($parent['mid']), - '$target_type' =>xmlify($target_type), - '$authorsig' => xmlify($authorsig), - '$body' => xmlify($text), - '$positive' => xmlify($positive), - '$handle' => xmlify($myaddr) - )); - - logger('diaspora_followup: base message: ' . $msg, LOGGER_DATA); - - $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['channel_prvkey'],$contact['xchan_pubkey'],$public_batch))); - - - return(diaspora_transmit($owner,$contact,$slap,$public_batch)); -} - - -function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { - - - $a = get_app(); - $myaddr = $owner['channel_address'] . '@' . get_app()->get_hostname(); - - $text = bb2diaspora_itembody($item); - - $body = $text; - - // Diaspora doesn't support threaded comments, but some - // versions of Diaspora (i.e. Diaspora-pistos) support - // likes on comments - - - // That version is now dead so detect a "sublike" and - // just send it as an activity. - - $sublike = false; - - - if($item['verb'] === ACTIVITY_LIKE && $item['thr_parent']) { - $sublike = true; - } - - - // The first item in the `item` table with the parent id is the parent. However, MySQL doesn't always - // return the items ordered by `item`.`id`, in which case the wrong item is chosen as the parent. - // The only item with `parent` and `id` as the parent id is the parent item. - $p = q("select * from item where parent = %d and id = %d limit 1", - intval($item['parent']), - intval($item['parent']) - ); - - if($p) - $parent = $p[0]; - else { - logger('diaspora_send_relay: no parent'); - return; - } - - $like = false; - $relay_retract = false; - $sql_sign_id = 'iid'; - - if( $item['item_restrict'] & ITEM_DELETED) { - $relay_retract = true; - - $target_type = ( ($item['verb'] === ACTIVITY_LIKE && (! $sublike)) ? 'Like' : 'Comment'); - - $sql_sign_id = 'retract_iid'; - $tpl = get_markup_template('diaspora_relayable_retraction.tpl'); - } - elseif(($item['verb'] === ACTIVITY_LIKE) && (! $sublike)) { - $like = true; - - $target_type = ( $parent['mid'] === $parent['parent_mid'] ? 'Post' : 'Comment'); -// $positive = (($item['item_restrict'] & ITEM_DELETED) ? 'false' : 'true'); - $positive = 'true'; - - $tpl = get_markup_template('diaspora_like_relay.tpl'); - } - else { // item is a comment - $tpl = get_markup_template('diaspora_comment_relay.tpl'); - } - - $diaspora_meta = (($item['diaspora_meta']) ? json_decode($item['diaspora_meta'],true) : ''); - if($diaspora_meta) { - if(array_key_exists('iv',$diaspora_meta)) { - $key = get_config('system','prvkey'); - $meta = json_decode(crypto_unencapsulate($diaspora_meta,$key),true); - } - else - $meta = $diaspora_meta; - $sender_signed_text = $meta['signed_text']; - $authorsig = $meta['signature']; - $handle = $meta['signer']; - $text = $meta['body']; - } - else - logger('diaspora_send_relay: original author signature not found'); - - /* Since the author signature is only checked by the parent, not by the relay recipients, - * I think it may not be necessary for us to do so much work to preserve all the original - * signatures. The important thing that Diaspora DOES need is the original creator's handle. - * Let's just generate that and forget about all the original author signature stuff. - * - * Note: this might be more of an problem if we want to support likes on comments for older - * versions of Diaspora (diaspora-pistos), but since there are a number of problems with - * doing that, let's ignore it for now. - * - * - */ -// bug - nomadic identity may/will affect diaspora_handle_from_contact - if(! $handle) { - if($item['author_xchan'] === $owner['channel_hash']) - $handle = $owner['channel_address'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3); - else - $handle = diaspora_handle_from_contact($item['author_xchan']); - } - if(! $handle) { - logger('diaspora_send_relay: no handle'); - return; - } - - if(! $sender_signed_text) { - if($relay_retract) - $sender_signed_text = $item['mid'] . ';' . $target_type; - elseif($like) - $sender_signed_text = $positive . ';' . $item['mid'] . ';' . $target_type . ';' . $parent['mid'] . ';' . $handle; - else - $sender_signed_text = $item['mid'] . ';' . $parent['mid'] . ';' . $text . ';' . $handle; - } - - // Sign the relayable with the top-level owner's signature - // - // We'll use the $sender_signed_text that we just created, instead of the $signed_text - // stored in the database, because that provides the best chance that Diaspora will - // be able to reconstruct the signed text the same way we did. This is particularly a - // concern for the comment, whose signed text includes the text of the comment. The - // smallest change in the text of the comment, including removing whitespace, will - // make the signature verification fail. Since we translate from BB code to Diaspora's - // markup at the top of this function, which is AFTER we placed the original $signed_text - // in the database, it's hazardous to trust the original $signed_text. - - $parentauthorsig = base64_encode(rsa_sign($sender_signed_text,$owner['channel_prvkey'],'sha256')); - - if(! $text) - logger('diaspora_send_relay: no text'); - - $msg = replace_macros($tpl,array( - '$guid' => xmlify($item['mid']), - '$parent_guid' => xmlify($parent['mid']), - '$target_type' =>xmlify($target_type), - '$authorsig' => xmlify($authorsig), - '$parentsig' => xmlify($parentauthorsig), - '$body' => xmlify($text), - '$positive' => xmlify($positive), - '$handle' => xmlify($handle) - )); - - logger('diaspora_send_relay: base message: ' . $msg, LOGGER_DATA); - - $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['channel_prvkey'],$contact['xchan_pubkey'],$public_batch))); - - return(diaspora_transmit($owner,$contact,$slap,$public_batch)); - -} - - - -function diaspora_send_retraction($item,$owner,$contact,$public_batch = false) { - - $a = get_app(); - $myaddr = $owner['channel_address'] . '@' . get_app()->get_hostname(); - - // Check whether the retraction is for a top-level post or whether it's a relayable - if( $item['mid'] !== $item['parent_mid'] ) { - - $tpl = get_markup_template('diaspora_relay_retraction.tpl'); - $target_type = (($item['verb'] === ACTIVITY_LIKE) ? 'Like' : 'Comment'); - } - else { - - $tpl = get_markup_template('diaspora_signed_retract.tpl'); - $target_type = 'StatusMessage'; - } - - $signed_text = $item['mid'] . ';' . $target_type; - - $msg = replace_macros($tpl, array( - '$guid' => xmlify($item['mid']), - '$type' => xmlify($target_type), - '$handle' => xmlify($myaddr), - '$signature' => xmlify(base64_encode(rsa_sign($signed_text,$owner['channel_prvkey'],'sha256'))) - )); - - $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['channel_prvkey'],$contact['xchan_pubkey'],$public_batch))); - - return(diaspora_transmit($owner,$contact,$slap,$public_batch)); -} - -function diaspora_send_mail($item,$owner,$contact) { - - $a = get_app(); - $myaddr = $owner['channel_address'] . '@' . get_app()->get_hostname(); - - $r = q("select * from conv where id = %d and uid = %d limit 1", - intval($item['convid']), - intval($item['channel_id']) - ); - - if(! count($r)) { - logger('diaspora_send_mail: conversation not found.'); - return; - } - $cnv = $r[0]; - - $conv = array( - 'guid' => xmlify($cnv['guid']), - 'subject' => xmlify($cnv['subject']), - 'created_at' => xmlify(datetime_convert('UTC','UTC',$cnv['created'],'Y-m-d H:i:s \U\T\C')), - 'diaspora_handle' => xmlify($cnv['creator']), - 'participant_handles' => xmlify($cnv['recips']) - ); - - if(array_key_exists('mail_flags',$item) && ($item['mail_flags'] & MAIL_OBSCURED)) { - $key = get_config('system','prvkey'); -// if($item['title']) -// $item['title'] = crypto_unencapsulate(json_decode_plus($item['title']),$key); - if($item['body']) - $item['body'] = crypto_unencapsulate(json_decode_plus($item['body']),$key); - } - - - $body = bb2diaspora($item['body']); - $created = datetime_convert('UTC','UTC',$item['created'],'Y-m-d H:i:s \U\T\C'); - - $signed_text = $item['mid'] . ';' . $cnv['guid'] . ';' . $body . ';' - . $created . ';' . $myaddr . ';' . $cnv['guid']; - - $sig = base64_encode(rsa_sign($signed_text,$owner['channel_prvkey'],'sha256')); - - $msg = array( - 'guid' => xmlify($item['mid']), - 'parent_guid' => xmlify($cnv['guid']), - 'parent_author_signature' => (($item['reply']) ? null : xmlify($sig)), - 'author_signature' => xmlify($sig), - 'text' => xmlify($body), - 'created_at' => xmlify($created), - 'diaspora_handle' => xmlify($myaddr), - 'conversation_guid' => xmlify($cnv['guid']) - ); - - if($item['reply']) { - $tpl = get_markup_template('diaspora_message.tpl'); - $xmsg = replace_macros($tpl, array('$msg' => $msg)); - } - else { - $conv['messages'] = array($msg); - $tpl = get_markup_template('diaspora_conversation.tpl'); - $xmsg = replace_macros($tpl, array('$conv' => $conv)); - } - - logger('diaspora_conversation: ' . print_r($xmsg,true), LOGGER_DATA); - - $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($xmsg,$owner,$contact,$owner['channel_prvkey'],$contact['xchan_pubkey'],false))); - - return(diaspora_transmit($owner,$contact,$slap,false)); - - -} - -function diaspora_transmit($owner,$contact,$slap,$public_batch,$queue_run=false) { - - $enabled = intval(get_config('system','diaspora_enabled')); - if(! $enabled) { - return 200; - } - - $allowed = get_pconfig($owner['channel_id'],'system','diaspora_allowed'); - if($allowed === false) - $allowed = 1; - - if(! intval($allowed)) { - return 200; - } - - if($public_batch) - $dest_url = $contact['hubloc_callback'] . '/public'; - else - $dest_url = $contact['hubloc_callback'] . '/users/' . $contact['hubloc_guid']; - - logger('diaspora_transmit: URL: ' . $dest_url, LOGGER_DEBUG); - - if(intval(get_config('system','diaspora_test'))) - return 200; - - $a = get_app(); - $logid = random_string(4); - - logger('diaspora_transmit: ' . $logid . ' ' . $dest_url, LOGGER_DEBUG); - - $hash = random_string(); - - $interval = ((get_config('system','delivery_interval') !== false) - ? intval(get_config('system','delivery_interval')) : 2 ); - - q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", - dbesc($hash), - intval($owner['account_id']), - intval($owner['channel_id']), - dbesc('post'), - dbesc($dest_url), - intval(1), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc(''), - dbesc($slap) - ); - - proc_run('php','include/deliver.php',$hash); - if($interval) - @time_sleep_until(microtime(true) + (float) $interval); - -} diff --git a/include/dir_fns.php b/include/dir_fns.php index 83073154a..e466b7404 100644 --- a/include/dir_fns.php +++ b/include/dir_fns.php @@ -151,16 +151,18 @@ function sync_directories($dirmode) { $realm = get_directory_realm(); if ($realm == DIRECTORY_REALM) { - $r = q("select * from site where (site_flags & %d) > 0 and site_url != '%s' and ( site_realm = '%s' or site_realm = '') ", + $r = q("select * from site where (site_flags & %d) > 0 and site_url != '%s' and site_type = %d and ( site_realm = '%s' or site_realm = '') ", intval(DIRECTORY_MODE_PRIMARY|DIRECTORY_MODE_SECONDARY), dbesc(z_root()), + intval(SITE_TYPE_ZOT), dbesc($realm) ); } else { - $r = q("select * from site where (site_flags & %d) > 0 and site_url != '%s' and site_realm like '%s' ", + $r = q("select * from site where (site_flags & %d) > 0 and site_url != '%s' and site_realm like '%s' and site_type = %d ", intval(DIRECTORY_MODE_PRIMARY|DIRECTORY_MODE_SECONDARY), dbesc(z_root()), - dbesc(protect_sprintf('%' . $realm . '%')) + dbesc(protect_sprintf('%' . $realm . '%')), + intval(SITE_TYPE_ZOT) ); } @@ -187,9 +189,10 @@ function sync_directories($dirmode) { intval($r[0]['site_valid']) ); - $r = q("select * from site where (site_flags & %d) > 0 and site_url != '%s'", + $r = q("select * from site where (site_flags & %d) > 0 and site_url != '%s' and site_type = %d ", intval(DIRECTORY_MODE_PRIMARY|DIRECTORY_MODE_SECONDARY), - dbesc(z_root()) + dbesc(z_root()), + intval(SITE_TYPE_ZOT) ); } if (! $r) @@ -389,19 +392,13 @@ function local_dir_update($uid, $force) { logger('hidden: ' . $hidden); - $r = q("select xchan_flags from xchan where xchan_hash = '%s' limit 1", + $r = q("select xchan_hidden from xchan where xchan_hash = '%s' limit 1", dbesc($p[0]['channel_hash']) ); - // Be careful - XCHAN_FLAGS_HIDDEN should evaluate to 1 - if (($r[0]['xchan_flags'] & XCHAN_FLAGS_HIDDEN) != $hidden) - $new_flags = $r[0]['xchan_flags'] ^ XCHAN_FLAGS_HIDDEN; - else - $new_flags = $r[0]['xchan_flags']; - - if ($new_flags != $r[0]['xchan_flags']) { - $r = q("update xchan set xchan_flags = %d where xchan_hash = '%s'", - intval($new_flags), + if(intval($r[0]['xchan_hidden']) != $hidden) { + $r = q("update xchan set xchan_hidden = %d where xchan_hash = '%s'", + intval($hidden), dbesc($p[0]['channel_hash']) ); } diff --git a/include/enotify.php b/include/enotify.php index b1aae816b..d0228bf50 100644 --- a/include/enotify.php +++ b/include/enotify.php @@ -36,9 +36,8 @@ function notification($params) { } if ($params['to_xchan']) { $y = q("select channel.*, account.* from channel left join account on channel_account_id = account_id - where channel_hash = '%s' and not (channel_pageflags & %d)>0 limit 1", - dbesc($params['to_xchan']), - intval(PAGE_REMOVED) + where channel_hash = '%s' and channel_removed = 0 limit 1", + dbesc($params['to_xchan']) ); } if ($x & $y) { @@ -82,8 +81,9 @@ function notification($params) { localize_item($i); $title = $i['title']; $body = $i['body']; - $private = (($i['item_private']) || ($i['item_flags'] & ITEM_OBSCURED)); - } else { + $private = (($i['item_private']) || intval($i['item_obscured'])); + } + else { $title = $params['item']['title']; $body = $params['item']['body']; } @@ -171,7 +171,7 @@ function notification($params) { $item_post_type); // "your post" - if($p[0]['owner']['xchan_name'] == $p[0]['author']['xchan_name'] && ($p[0]['item_flags'] & ITEM_WALL)) + if($p[0]['owner']['xchan_name'] == $p[0]['author']['xchan_name'] && intval($p[0]['item_wall'])) $dest_str = sprintf(t('%1$s, %2$s commented on [zrl=%3$s]your %4$s[/zrl]'), $recip['channel_name'], '[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]', @@ -642,4 +642,4 @@ class enotify { ); logger("notification: enotify::send returns " . $res, LOGGER_DEBUG); } -}
\ No newline at end of file +} diff --git a/include/event.php b/include/event.php index 3b48837f1..e303ad232 100644 --- a/include/event.php +++ b/include/event.php @@ -63,9 +63,9 @@ function ical_wrapper($ev) { return ''; $o .= "BEGIN:VCALENDAR"; - $o .= "\nVERSION:2.0"; - $o .= "\nMETHOD:PUBLISH"; - $o .= "\nPRODID:-//" . get_config('system','sitename') . "//" . PLATFORM_NAME . "//" . strtoupper(get_app()->language). "\n"; + $o .= "\r\nVERSION:2.0"; + $o .= "\r\nMETHOD:PUBLISH"; + $o .= "\r\nPRODID:-//" . get_config('system','sitename') . "//" . PLATFORM_NAME . "//" . strtoupper(get_app()->language). "\r\n"; if(array_key_exists('start', $ev)) $o .= format_event_ical($ev); else { @@ -73,38 +73,84 @@ function ical_wrapper($ev) { $o .= format_event_ical($e); } } - $o .= "\nEND:VCALENDAR\n"; + $o .= "\r\nEND:VCALENDAR\r\n"; return $o; } function format_event_ical($ev) { + if($ev['type'] === 'task') + return format_todo_ical($ev); + $o = ''; - $o .= "\nBEGIN:VEVENT"; + $o .= "\r\nBEGIN:VEVENT"; + + $o .= "\r\nCREATED:" . datetime_convert('UTC','UTC', $ev['created'],'Ymd\\THis\\Z'); + $o .= "\r\nLAST-MODIFIED:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z'); + $o .= "\r\nDTSTAMP:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z'); if($ev['start']) - $o .= "\nDTSTART:" . datetime_convert('UTC','UTC', $ev['start'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : '')); + $o .= "\r\nDTSTART:" . datetime_convert('UTC','UTC', $ev['start'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : '')); if($ev['finish'] && ! $ev['nofinish']) - $o .= "\nDTEND:" . datetime_convert('UTC','UTC', $ev['finish'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : '')); + $o .= "\r\nDTEND:" . datetime_convert('UTC','UTC', $ev['finish'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : '')); if($ev['summary']) - $o .= "\nSUMMARY:" . format_ical_text($ev['summary']); + $o .= "\r\nSUMMARY:" . format_ical_text($ev['summary']); if($ev['location']) - $o .= "\nLOCATION:" . format_ical_text($ev['location']); + $o .= "\r\nLOCATION:" . format_ical_text($ev['location']); if($ev['description']) - $o .= "\nDESCRIPTION:" . format_ical_text($ev['description']); - $o .= "\nUID:" . $ev['event_hash'] ; - $o .= "\nEND:VEVENT\n"; + $o .= "\r\nDESCRIPTION:" . format_ical_text($ev['description']); + if($ev['event_priority']) + $o .= "\r\nPRIORITY:" . intval($ev['event_priority']); + $o .= "\r\nUID:" . $ev['event_hash'] ; + $o .= "\r\nEND:VEVENT\r\n"; + + return $o; +} + + +function format_todo_ical($ev) { + + $o = ''; + + $o .= "\r\nBEGIN:VTODO"; + $o .= "\r\nCREATED:" . datetime_convert('UTC','UTC', $ev['created'],'Ymd\\THis\\Z'); + $o .= "\r\nLAST-MODIFIED:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z'); + $o .= "\r\nDTSTAMP:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z'); + if($ev['start']) + $o .= "\r\nDTSTART:" . datetime_convert('UTC','UTC', $ev['start'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : '')); + if($ev['finish'] && ! $ev['nofinish']) + $o .= "\r\nDUE:" . datetime_convert('UTC','UTC', $ev['finish'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : '')); + if($ev['summary']) + $o .= "\r\nSUMMARY:" . format_ical_text($ev['summary']); + if($ev['event_status']) { + $o .= "\r\nSTATUS:" . $ev['event_status']; + if($ev['event_status'] === 'COMPLETED') + $o .= "\r\nCOMPLETED:" . datetime_convert('UTC','UTC', $ev['event_status_date'],'Ymd\\THis\\Z'); + } + if(intval($ev['event_percent'])) + $o .= "\r\nPERCENT-COMPLETE:" . $ev['event_percent']; + if(intval($ev['event_sequence'])) + $o .= "\r\nSEQUENCE:" . $ev['event_sequence']; + if($ev['location']) + $o .= "\r\nLOCATION:" . format_ical_text($ev['location']); + if($ev['description']) + $o .= "\r\nDESCRIPTION:" . format_ical_text($ev['description']); + $o .= "\r\nUID:" . $ev['event_hash'] ; + if($ev['event_priority']) + $o .= "\r\nPRIORITY:" . intval($ev['event_priority']); + $o .= "\r\nEND:VTODO\r\n"; return $o; } + function format_ical_text($s) { require_once('include/bbcode.php'); require_once('include/html2plain.php'); - return(wordwrap(str_replace(',','\\,',html2plain(bbcode($s))),72,"\n ",true)); + return(wordwrap(str_replace(array(',',';','\\'),array('\\,','\\;','\\\\'),html2plain(bbcode($s))),72,"\r\n ",true)); } @@ -218,11 +264,17 @@ function ev_compare($a, $b) { function event_store_event($arr) { - $arr['created'] = (($arr['created']) ? $arr['created'] : datetime_convert()); - $arr['edited'] = (($arr['edited']) ? $arr['edited'] : datetime_convert()); - $arr['type'] = (($arr['type']) ? $arr['type'] : 'event' ); - $arr['event_xchan'] = (($arr['event_xchan']) ? $arr['event_xchan'] : ''); + $arr['created'] = (($arr['created']) ? $arr['created'] : datetime_convert()); + $arr['edited'] = (($arr['edited']) ? $arr['edited'] : datetime_convert()); + $arr['type'] = (($arr['type']) ? $arr['type'] : 'event' ); + $arr['event_xchan'] = (($arr['event_xchan']) ? $arr['event_xchan'] : ''); + $arr['event_priority'] = (($arr['event_priority']) ? $arr['event_priority'] : 0); + + if(array_key_exists('event_status_date',$arr)) + $arr['event_status_date'] = datetime_convert('UTC','UTC', $arr['event_status_date']); + else + $arr['event_status_date'] = NULL_DATE; // Existing event being modified @@ -265,6 +317,12 @@ function event_store_event($arr) { `type` = '%s', `adjust` = %d, `nofinish` = %d, + `event_status` = '%s', + `event_status_date` = '%s', + `event_percent` = %d, + `event_repeat` = '%s', + `event_sequence` = %d, + `event_priority` = %d, `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', @@ -280,6 +338,12 @@ function event_store_event($arr) { dbesc($arr['type']), intval($arr['adjust']), intval($arr['nofinish']), + dbesc($arr['event_status']), + dbesc($arr['event_status_date']), + intval($arr['event_percent']), + dbesc($arr['event_repeat']), + intval($arr['event_sequence']), + intval($arr['event_priority']), dbesc($arr['allow_cid']), dbesc($arr['allow_gid']), dbesc($arr['deny_cid']), @@ -298,8 +362,8 @@ function event_store_event($arr) { $hash = random_string() . '@' . get_app()->get_hostname(); $r = q("INSERT INTO event ( uid,aid,event_xchan,event_hash,created,edited,start,finish,summary,description,location,type, - adjust,nofinish,allow_cid,allow_gid,deny_cid,deny_gid) - VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s' ) ", + adjust,nofinish, event_status, event_status_date, event_percent, event_repeat, event_sequence, event_priority, allow_cid,allow_gid,deny_cid,deny_gid) + VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', %d, '%s', %d, %d, '%s', '%s', '%s', '%s' ) ", intval($arr['uid']), intval($arr['account']), dbesc($arr['event_xchan']), @@ -314,6 +378,12 @@ function event_store_event($arr) { dbesc($arr['type']), intval($arr['adjust']), intval($arr['nofinish']), + dbesc($arr['event_status']), + dbesc($arr['event_status_date']), + intval($arr['event_percent']), + dbesc($arr['event_repeat']), + intval($arr['event_sequence']), + intval($arr['event_priority']), dbesc($arr['allow_cid']), dbesc($arr['allow_gid']), dbesc($arr['deny_cid']), @@ -413,9 +483,15 @@ require_once('vendor/autoload.php'); $ical = VObject\Reader::read($s); if($ical) { - foreach($ical->VEVENT as $event) { - event_import_ical($event,$uid); - + if($ical->VEVENT) { + foreach($ical->VEVENT as $event) { + event_import_ical($event,$uid); + } + } + if($ical->VTODO) { + foreach($ical->VTODO as $event) { + event_import_ical_task($event,$uid); + } } } @@ -450,6 +526,105 @@ function event_import_ical($ical, $uid) { // logger('dtstart: ' . var_export($dtstart,true)); + + switch($dtstart->timezone_type) { + case VObject\Property\DateTime::UTC : + $ev['adjust'] = 0; + break; + case VObject\Property\DateTime::LOCALTZ : + default: + $ev['adjust'] = 1; + break; + } + + $ev['start'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),'UTC', + $dtstart->format(\DateTime::W3C)); + + + if(isset($ical->DTEND)) { + $dtend = $ical->DTEND->getDateTime(); + $ev['finish'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),'UTC', + $dtend->format(\DateTime::W3C)); + } + else + $ev['nofinish'] = 1; + + + if($ev['start'] === $ev['finish']) + $ev['nofinish'] = 1; + + if(isset($ical->CREATED)) { + $created = $ical->CREATED->getDateTime(); + $ev['created'] = datetime_convert('UTC','UTC',$created->format(\DateTime::W3C)); + } + + if(isset($ical->{'LAST-MODIFIED'})) { + $edited = $ical->{'LAST-MODIFIED'}->getDateTime(); + $ev['edited'] = datetime_convert('UTC','UTC',$edited->format(\DateTime::W3C)); + } + + if(isset($ical->LOCATION)) + $ev['location'] = (string) $ical->LOCATION; + if(isset($ical->DESCRIPTION)) + $ev['description'] = (string) $ical->DESCRIPTION; + if(isset($ical->SUMMARY)) + $ev['summary'] = (string) $ical->SUMMARY; + if(isset($ical->PRIORITY)) + $ev['event_priority'] = intval((string) $ical->PRIORITY); + + if(isset($ical->UID)) { + $evuid = (string) $ical->UID; + $r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1", + dbesc($evuid), + intval($uid) + ); + if($r) + $ev['event_hash'] = $evuid; + else + $ev['external_id'] = $evuid; + } + + if($ev['summary'] && $ev['start']) { + $ev['event_xchan'] = $channel['channel_hash']; + $ev['uid'] = $channel['channel_id']; + $ev['account'] = $channel['channel_account_id']; + $ev['private'] = 1; + $ev['allow_cid'] = '<' . $channel['channel_hash'] . '>'; + + logger('storing event: ' . print_r($ev,true), LOGGER_ALL); + $event = event_store_event($ev); + if($event) { + $item_id = event_store_item($ev,$event); + return true; + } + } + + return false; + +} + +function event_import_ical_task($ical, $uid) { + + $c = q("select * from channel where channel_id = %d limit 1", + intval($uid) + ); + + if(! $c) + return false; + + $channel = $c[0]; + $ev = array(); + + + if(! isset($ical->DTSTART)) { + logger('no event start'); + return false; + } + + $dtstart = $ical->DTSTART->getDateTime(); + +// logger('dtstart: ' . var_export($dtstart,true)); + if(($dtstart->timezone_type == 2) || (($dtstart->timezone_type == 3) && ($dtstart->timezone === 'UTC'))) { $ev['adjust'] = 1; } @@ -461,8 +636,8 @@ function event_import_ical($ical, $uid) { $dtstart->format(\DateTime::W3C)); - if(isset($ical->DTEND)) { - $dtend = $ical->DTEND->getDateTime(); + if(isset($ical->DUE)) { + $dtend = $ical->DUE->getDateTime(); $ev['finish'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),'UTC', $dtend->format(\DateTime::W3C)); } @@ -478,6 +653,11 @@ function event_import_ical($ical, $uid) { $ev['created'] = datetime_convert('UTC','UTC',$created->format(\DateTime::W3C)); } + if(isset($ical->{'DTSTAMP'})) { + $edited = $ical->{'DTSTAMP'}->getDateTime(); + $ev['edited'] = datetime_convert('UTC','UTC',$edited->format(\DateTime::W3C)); + } + if(isset($ical->{'LAST-MODIFIED'})) { $edited = $ical->{'LAST-MODIFIED'}->getDateTime(); $ev['edited'] = datetime_convert('UTC','UTC',$edited->format(\DateTime::W3C)); @@ -489,6 +669,10 @@ function event_import_ical($ical, $uid) { $ev['description'] = (string) $ical->DESCRIPTION; if(isset($ical->SUMMARY)) $ev['summary'] = (string) $ical->SUMMARY; + if(isset($ical->PRIORITY)) + $ev['event_priority'] = intval((string) $ical->PRIORITY); + + $stored_event = null; if(isset($ical->UID)) { $evuid = (string) $ical->UID; @@ -496,12 +680,38 @@ function event_import_ical($ical, $uid) { dbesc($evuid), intval($uid) ); - if($r) + if($r) { $ev['event_hash'] = $evuid; - else + $stored_event = $r[0]; + } + else { $ev['external_id'] = $evuid; + } } - + + if(isset($ical->SEQUENCE)) { + $ev['event_sequence'] = (string) $ical->SEQUENCE; + // see if our stored event is more current than the one we're importing + if((intval($ev['event_sequence']) <= intval($stored_event['event_sequence'])) + && ($ev['edited'] <= $stored_event['edited'])) + return false; + } + + if(isset($ical->STATUS)) { + $ev['event_status'] = (string) $ical->STATUS; + } + + if(isset($ical->{'COMPLETED'})) { + $completed = $ical->{'COMPLETED'}->getDateTime(); + $ev['event_status_date'] = datetime_convert('UTC','UTC',$completed->format(\DateTime::W3C)); + } + + if(isset($ical->{'PERCENT-COMPLETE'})) { + $ev['event_percent'] = (string) $ical->{'PERCENT-COMPLETE'} ; + } + + $ev['type'] = 'task'; + if($ev['summary'] && $ev['start']) { $ev['event_xchan'] = $channel['channel_hash']; $ev['uid'] = $channel['channel_id']; @@ -522,6 +732,10 @@ function event_import_ical($ical, $uid) { } + + + + function event_store_item($arr, $event) { require_once('include/datetime.php'); @@ -541,12 +755,15 @@ function event_store_item($arr, $event) { } } + + $item_arr = array(); $prefix = ''; // $birthday = false; if($event['type'] === 'birthday') { - $prefix = t('This event has been added to your calendar.'); + if(! is_sys_channel($arr['uid'])) + $prefix = t('This event has been added to your calendar.'); // $birthday = true; // The event is created on your own site by the system, but appears to belong @@ -582,7 +799,12 @@ function event_store_item($arr, $event) { $private = (($arr['allow_cid'] || $arr['allow_gid'] || $arr['deny_cid'] || $arr['deny_gid']) ? 1 : 0); - q("UPDATE item SET title = '%s', body = '%s', object = '%s', allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', edited = '%s', item_flags = %d, item_private = %d, obj_type = '%s' WHERE id = %d AND uid = %d", + // @FIXME can only update sig if we have the author's channel on this site + // Until fixed, set it to nothing so it won't give us signature errors + + $sig = ''; + + q("UPDATE item SET title = '%s', body = '%s', object = '%s', allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', edited = '%s', sig = '%s', item_flags = %d, item_private = %d, obj_type = '%s' WHERE id = %d AND uid = %d", dbesc($arr['summary']), dbesc($prefix . format_event_bbcode($arr)), dbesc($object), @@ -591,6 +813,7 @@ function event_store_item($arr, $event) { dbesc($arr['deny_cid']), dbesc($arr['deny_gid']), dbesc($arr['edited']), + dbesc($sig), intval($r[0]['item_flags']), intval($private), dbesc(ACTIVITY_OBJ_EVENT), @@ -629,48 +852,61 @@ function event_store_item($arr, $event) { $private = (($arr['allow_cid'] || $arr['allow_gid'] || $arr['deny_cid'] || $arr['deny_gid']) ? 1 : 0); + $item_wall = 0; + $item_origin = 0; + $item_thread_top = 0; + if($item) { $item_arr['id'] = $item['id']; } else { $wall = (($z[0]['channel_hash'] == $event['event_xchan']) ? true : false); - - $item_flags = ITEM_THREAD_TOP; + $item_thread_top = 1; if($wall) { - $item_flags |= ITEM_WALL; - $item_flags |= ITEM_ORIGIN; + $item_wall = 1; + $item_origin = 1; } - $item_arr['item_flags'] = $item_flags; } if(! $arr['mid']) $arr['mid'] = item_message_id(); - $item_arr['aid'] = $z[0]['channel_account_id']; - $item_arr['uid'] = $arr['uid']; - $item_arr['author_xchan'] = $arr['event_xchan']; - $item_arr['mid'] = $arr['mid']; - $item_arr['parent_mid'] = $arr['mid']; - - $item_arr['owner_xchan'] = (($wall) ? $z[0]['channel_hash'] : $arr['event_xchan']); - $item_arr['author_xchan'] = $arr['event_xchan']; - $item_arr['title'] = $arr['summary']; - $item_arr['allow_cid'] = $arr['allow_cid']; - $item_arr['allow_gid'] = $arr['allow_gid']; - $item_arr['deny_cid'] = $arr['deny_cid']; - $item_arr['deny_gid'] = $arr['deny_gid']; - $item_arr['item_private'] = $private; - $item_arr['verb'] = ACTIVITY_POST; + $item_arr['aid'] = $z[0]['channel_account_id']; + $item_arr['uid'] = $arr['uid']; + $item_arr['author_xchan'] = $arr['event_xchan']; + $item_arr['mid'] = $arr['mid']; + $item_arr['parent_mid'] = $arr['mid']; + $item_arr['owner_xchan'] = (($wall) ? $z[0]['channel_hash'] : $arr['event_xchan']); + $item_arr['author_xchan'] = $arr['event_xchan']; + $item_arr['title'] = $arr['summary']; + $item_arr['allow_cid'] = $arr['allow_cid']; + $item_arr['allow_gid'] = $arr['allow_gid']; + $item_arr['deny_cid'] = $arr['deny_cid']; + $item_arr['deny_gid'] = $arr['deny_gid']; + $item_arr['item_private'] = $private; + $item_arr['verb'] = ACTIVITY_POST; + $item_arr['item_wall'] = $item_wall; + $item_arr['item_origin'] = $item_origin; + $item_arr['item_thread_top'] = $item_thread_top;; + + $attach = array(array( + 'href' => z_root() . '/events/ical/' . urlencode($event['event_hash']), + 'length' => 0, + 'type' => 'text/calendar', + 'title' => t('event') . '-' . $event['event_hash'], + 'revision' => '' + )); - if(array_key_exists('term', $arr)) - $item_arr['term'] = $arr['term']; + $item_arr['attach'] = $attach; - $item_arr['resource_type'] = 'event'; - $item_arr['resource_id'] = $event['event_hash']; - $item_arr['obj_type'] = ACTIVITY_OBJ_EVENT; + if(array_key_exists('term', $arr)) + $item_arr['term'] = $arr['term']; - $item_arr['body'] = $prefix . format_event_bbcode($arr); + $item_arr['resource_type'] = 'event'; + $item_arr['resource_id'] = $event['event_hash']; + $item_arr['obj_type'] = ACTIVITY_OBJ_EVENT; + $item_arr['body'] = $prefix . format_event_bbcode($arr); // if it's local send the permalink to the channel page. // otherwise we'll fallback to /display/$message_id @@ -710,3 +946,38 @@ function event_store_item($arr, $event) { return $item_id; } } + + +function todo_stat() { + return array( + '' => t('Not specified'), + 'NEEDS-ACTION' => t('Needs Action'), + 'COMPLETED' => t('Completed'), + 'IN-PROCESS' => t('In Process'), + 'CANCELLED' => t('Cancelled') + ); +} + + +function tasks_fetch($arr) { + + if(! local_channel()) + return; + + $ret = array(); + $sql_extra = " and event_status != 'COMPLETED' "; + if($arr && $arr['all'] == 1) + $sql_extra = ''; + + $r = q("select * from event where type = 'task' and uid = %d $sql_extra order by created desc", + intval(local_channel()) + ); + + $ret['success'] = (($r) ? true : false); + if($r) { + $ret['tasks'] = $r; + } + + return $ret; + +} diff --git a/include/expire.php b/include/expire.php index e5d456896..e75594b5f 100644 --- a/include/expire.php +++ b/include/expire.php @@ -12,10 +12,7 @@ function expire_run($argv, $argc){ // perform final cleanup on previously delete items - $r = q("select id from item where (item_restrict & %d) > 0 and (item_restrict & %d) = 0 - and changed < %s - INTERVAL %s", - intval(ITEM_DELETED), - intval(ITEM_PENDING_REMOVE), + $r = q("select id from item where item_deleted = 1 and item_pending_remove = 0 and changed < %s - INTERVAL %s", db_utcnow(), db_quoteinterval('10 DAY') ); if ($r) { @@ -27,8 +24,7 @@ function expire_run($argv, $argc){ // physically remove anything that has been deleted for more than two months /** @FIXME - this is a wretchedly inefficient query */ - $r = q("delete from item where ( item_restrict & %d ) > 0 and changed < %s - INTERVAL %s", - intval(ITEM_PENDING_REMOVE), + $r = q("delete from item where item_pending_remove = 1 and changed < %s - INTERVAL %s", db_utcnow(), db_quoteinterval('36 DAY') ); @@ -49,7 +45,7 @@ function expire_run($argv, $argc){ foreach ($r as $rr) { // expire the sys channel separately - if ($rr['channel_pageflags'] & PAGE_SYSTEM) + if (intval($rr['channel_system'])) continue; // service class default (if non-zero) over-rides the site default diff --git a/include/externals.php b/include/externals.php index b0f853dc6..18c034bb2 100644 --- a/include/externals.php +++ b/include/externals.php @@ -28,9 +28,10 @@ function externals_run($argv, $argc){ } else { $randfunc = db_getfunc('RAND'); - $r = q("select site_url, site_pull from site where site_url != '%s' and site_flags != %d order by $randfunc limit 1", + $r = q("select site_url, site_pull from site where site_url != '%s' and site_flags != %d and site_type = %d order by $randfunc limit 1", dbesc(z_root()), - intval(DIRECTORY_MODE_STANDALONE) + intval(DIRECTORY_MODE_STANDALONE), + intval(SITE_TYPE_ZOT) ); if($r) $url = $r[0]['site_url']; @@ -93,26 +94,6 @@ function externals_run($argv, $argc){ $results = process_delivery(array('hash' => 'undefined'), get_item_elements($message), array(array('hash' => $sys['xchan_hash'])), false, true); $total ++; -// $z = q("select id from item where mid = '%s' and uid = %d limit 1", -// dbesc($message['message_id']), -// intval($sys['channel_id']) -// ); -$z = null; - if($z) { - $flag_bits = ITEM_WALL|ITEM_ORIGIN|ITEM_UPLINK; - // preserve the source - - $r = q("update item set source_xchan = owner_xchan where id = %d", - intval($z[0]['id']) - ); - - $r = q("update item set item_flags = ( item_flags | %d ), owner_xchan = '%s' - where id = %d", - intval($flag_bits), - dbesc($sys['xchan_hash']), - intval($z[0]['id']) - ); - } } logger('externals: import_public_posts: ' . $total . ' messages imported', LOGGER_DEBUG); } diff --git a/include/follow.php b/include/follow.php index 54e16703d..960138743 100644 --- a/include/follow.php +++ b/include/follow.php @@ -37,9 +37,8 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) // check service class limits - $r = q("select count(*) as total from abook where abook_channel = %d and not (abook_flags & %d)>0 ", - intval($uid), - intval(ABOOK_FLAG_SELF) + $r = q("select count(*) as total from abook where abook_channel = %d and abook_self = 0 ", + intval($uid) ); if($r) $total_channels = $r[0]['total']; @@ -130,21 +129,6 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) } } else { - if(! ($is_http)) { - if(! intval(get_config('system','diaspora_enabled'))) { - $result['message'] = t('Protocol disabled.'); - return $result; - } - - $allowed = get_pconfig($uid,'system','diaspora_allowed'); - if($allowed === false) - $allowed = 1; - - if(! intval($allowed)) { - $result['message'] = t('Protocol blocked for this channel.'); - return $result; - } - } $their_perms = 0; $xchan_hash = ''; @@ -161,8 +145,15 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) } elseif($is_http) { $r = discover_by_url($url); + $r['allowed'] = intval(get_config('system','feed_contacts')); } if($r) { + $r['channel_id'] = $uid; + call_hooks('follow_allow',$r); + if(! $r['allowed']) { + $result['message'] = t('Protocol disabled.'); + return $result; + } $r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' limit 1", dbesc($url), dbesc($url) @@ -202,14 +193,9 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) if($is_http) { - if(! intval(get_config('system','feed_contacts'))) { - $result['message'] = t('Protocol disabled.'); - return $result; - } - $r = q("select count(*) as total from abook where abook_account = %d and ( abook_flags & %d )>0", - intval($aid), - intval(ABOOK_FLAG_FEED) + $r = q("select count(*) as total from abook where abook_account = %d and abook_feed = 1 ", + intval($aid) ); if($r) $total_feeds = $r[0]['total']; @@ -241,13 +227,13 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) if($closeness === false) $closeness = 80; - $r = q("insert into abook ( abook_account, abook_channel, abook_closeness, abook_xchan, abook_flags, abook_their_perms, abook_my_perms, abook_created, abook_updated ) + $r = q("insert into abook ( abook_account, abook_channel, abook_closeness, abook_xchan, abook_feed, abook_their_perms, abook_my_perms, abook_created, abook_updated ) values( %d, %d, %d, '%s', %d, %d, %d, '%s', '%s' ) ", intval($aid), intval($uid), intval($closeness), dbesc($xchan_hash), - intval(($is_http) ? ABOOK_FLAG_FEED : 0), + intval(($is_http) ? 1 : 0), intval(($is_http) ? $their_perms|PERMS_R_STREAM|PERMS_A_REPUBLISH : $their_perms), intval($my_perms), dbesc(datetime_convert()), diff --git a/include/gprobe.php b/include/gprobe.php index 48c1c8e14..d8d893d9e 100644 --- a/include/gprobe.php +++ b/include/gprobe.php @@ -14,6 +14,9 @@ function gprobe_run($argv, $argc){ $url = hex2bin($argv[1]); + if(! strpos($url,'@')) + return; + $r = q("select * from xchan where xchan_addr = '%s' limit 1", dbesc($url) ); diff --git a/include/group.php b/include/group.php index fe55ec23f..0875b10f9 100644 --- a/include/group.php +++ b/include/group.php @@ -200,13 +200,10 @@ function group_get_members($gid) { if(intval($gid)) { $r = q("SELECT * FROM `group_member` LEFT JOIN abook ON abook_xchan = `group_member`.`xchan` left join xchan on xchan_hash = abook_xchan - WHERE `gid` = %d AND abook_channel = %d and `group_member`.`uid` = %d and not ( xchan_flags & %d )>0 and not ( abook_flags & %d )>0 and not ( abook_flags & %d )>0 ORDER BY xchan_name ASC ", + WHERE `gid` = %d AND abook_channel = %d and `group_member`.`uid` = %d and xchan_deleted = 0 and abook_blocked = 0 and abook_pending = 0 ORDER BY xchan_name ASC ", intval($gid), intval(local_channel()), - intval(local_channel()), - intval(XCHAN_FLAGS_DELETED), - intval(ABOOK_FLAG_BLOCKED), - intval(ABOOK_FLAG_PENDING) + intval(local_channel()) ); if(count($r)) $ret = $r; @@ -232,7 +229,7 @@ function mini_group_select($uid,$group = '') { logger('mini_group_select: ' . print_r($grps,true), LOGGER_DATA); $o = replace_macros(get_markup_template('group_selection.tpl'), array( - '$label' => t('Default privacy group for new contacts'), + '$label' => t('Add new connections to this collection (privacy group)'), '$groups' => $grps )); return $o; @@ -245,7 +242,7 @@ function group_side($every="connections",$each="group",$edit = false, $group_id $o = ''; - if(! local_channel()) + if(! (local_channel() && feature_enabled(local_channel(),'groups'))) return ''; $groups = array(); diff --git a/include/hubloc.php b/include/hubloc.php index a4efe1c75..a1171b0e2 100644 --- a/include/hubloc.php +++ b/include/hubloc.php @@ -16,7 +16,9 @@ function is_matrix_url($url) { function prune_hub_reinstalls() { - $r = q("select site_url from site where true"); + $r = q("select site_url from site where site_type = %d", + intval(SITE_TYPE_ZOT) + ); if($r) { foreach($r as $rr) { $x = q("select count(*) as t, hubloc_sitekey, max(hubloc_connected) as c from hubloc where hubloc_url = '%s' group by hubloc_sitekey order by c", @@ -96,8 +98,7 @@ function remove_obsolete_hublocs() { ? intval(get_config('system','delivery_interval')) : 2 ); foreach($r as $rr) { - q("update hubloc set hubloc_flags = (hubloc_flags | %d) where hubloc_id = %d", - intval(HUBLOC_FLAGS_DELETED), + q("update hubloc set hubloc_deleted = 1 where hubloc_id = %d", intval($rr['hubloc_id']) ); @@ -121,7 +122,7 @@ function hubloc_change_primary($hubloc) { logger('no hubloc'); return false; } - if(! ($hubloc['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY)) { + if(! (intval($hubloc['hubloc_primary']))) { logger('not primary: ' . $hubloc['hubloc_url']); return false; } @@ -206,7 +207,7 @@ function xchan_store($arr) { if(! $arr['photo']) $arr['photo'] = z_root() . '/' . get_default_profile_photo(); - $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_guid_sig, xchan_pubkey, xchan_addr, xchan_url, xchan_connurl, xchan_follow, xchan_connpage, xchan_name, xchan_network, xchan_instance_url, xchan_flags, xchan_name_date ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s','%s','%s','%s',%d,'%s') ", + $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_guid_sig, xchan_pubkey, xchan_addr, xchan_url, xchan_connurl, xchan_follow, xchan_connpage, xchan_name, xchan_network, xchan_instance_url, xchan_hidden, xchan_orphan, xchan_censored, xchan_selfcensored, xchan_system, xchan_pubforum, xchan_deleted, xchan_name_date ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s','%s','%s','%s',%d, %d, %d, %d, %d, %d, %d, '%s') ", dbesc($arr['hash']), dbesc($arr['guid']), dbesc($arr['guid_sig']), @@ -219,13 +220,19 @@ function xchan_store($arr) { dbesc($arr['name']), dbesc($arr['network']), dbesc($arr['instance_url']), - intval($arr['flags']), + intval($arr['hidden']), + intval($arr['orphan']), + intval($arr['censored']), + intval($arr['selfcensored']), + intval($arr['system']), + intval($arr['pubforum']), + intval($arr['deleted']), dbesc(datetime_convert()) ); if(! $r) return $r; - $photos = import_profile_photo($arr['photo'],$arr['hash']); + $photos = import_xchan_photo($arr['photo'],$arr['hash']); $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", dbesc(datetime_convert()), dbesc($photos[0]), @@ -270,4 +277,34 @@ function xchan_fetch($arr) { $ret[str_replace('xchan_','',$k)] = $v; } return $ret; -}
\ No newline at end of file +} + + + +function ping_site($url) { + + $ret = array('success' => false); + + $sys = get_sys_channel(); + + $m = zot_build_packet($sys,'ping'); + $r = zot_zot($url . '/post',$m); + if(! $r['success']) { + $ret['message'] = 'no answer from ' . $url; + return $ret; + } + $packet_result = json_decode($r['body'],true); + if(! $packet_result['success']) { + $ret['message'] = 'packet failure from ' . $url; + return $ret; + } + + if($packet_result['success']) { + $ret['success'] = true; + } + else { + $ret['message'] = 'unknown error from ' . $url; + } + + return $ret; +} diff --git a/include/identity.php b/include/identity.php index d84c22693..47738a8fa 100644 --- a/include/identity.php +++ b/include/identity.php @@ -24,9 +24,8 @@ require_once('include/menu.php'); function identity_check_service_class($account_id) { $ret = array('success' => false, 'message' => ''); - $r = q("select count(channel_id) as total from channel where channel_account_id = %d and not ( channel_pageflags & %d )>0 ", - intval($account_id), - intval(PAGE_REMOVED) + $r = q("select count(channel_id) as total from channel where channel_account_id = %d and channel_removed = 0 ", + intval($account_id) ); if(! ($r && count($r))) { $ret['total_identities'] = 0; @@ -98,9 +97,9 @@ function create_sys_channel() { 'account_id' => 'xxx', // This will create an identity with an (integer) account_id of 0, but account_id is required 'nickname' => 'sys', 'name' => 'System', - 'pageflags' => PAGE_SYSTEM, + 'pageflags' => 0, 'publish' => 0, - 'xchanflags' => XCHAN_FLAGS_SYSTEM + 'system' => 1 )); } @@ -111,9 +110,7 @@ function create_sys_channel() { * @return array|boolean */ function get_sys_channel() { - $r = q("select * from channel left join xchan on channel_hash = xchan_hash where (channel_pageflags & %d)>0 limit 1", - intval(PAGE_SYSTEM) - ); + $r = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_system = 1 limit 1"); if ($r) return $r[0]; @@ -129,11 +126,11 @@ function get_sys_channel() { * @return boolean */ function is_sys_channel($channel_id) { - $r = q("select channel_pageflags from channel where channel_id = %d limit 1", + $r = q("select channel_system from channel where channel_id = %d and channel_system = 1 limit 1", intval($channel_id) ); - if (($r) && ($r[0]['channel_pageflags'] & PAGE_SYSTEM)) + if($r) return true; return false; @@ -149,9 +146,7 @@ function is_sys_channel($channel_id) { * on error returns boolean false */ function channel_total() { - $r = q("select channel_id from channel where not ( channel_pageflags & %d )>0", - intval(PAGE_REMOVED) - ); + $r = q("select channel_id from channel where channel_removed = 0"); if (is_array($r)) return count($r); @@ -201,14 +196,14 @@ function create_identity($arr) { $name = escape_tags($arr['name']); $pageflags = ((x($arr,'pageflags')) ? intval($arr['pageflags']) : PAGE_NORMAL); - $xchanflags = ((x($arr,'xchanflags')) ? intval($arr['xchanflags']) : XCHAN_FLAGS_NORMAL); + $system = ((x($arr,'system')) ? intval($arr['system']) : 0); $name_error = validate_channelname($arr['name']); if($name_error) { $ret['message'] = $name_error; return $ret; } - if($nick === 'sys' && (! ($pageflags & PAGE_SYSTEM))) { + if($nick === 'sys' && (! $system)) { $ret['message'] = t('Reserved nickname. Please choose another.'); return $ret; } @@ -265,8 +260,8 @@ function create_identity($arr) { $r = q("insert into channel ( channel_account_id, channel_primary, channel_name, channel_address, channel_guid, channel_guid_sig, - channel_hash, channel_prvkey, channel_pubkey, channel_pageflags, channel_expire_days, channel_timezone $perms_keys ) - values ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s' $perms_vals ) ", + channel_hash, channel_prvkey, channel_pubkey, channel_pageflags, channel_system, channel_expire_days, channel_timezone $perms_keys ) + values ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s' $perms_vals ) ", intval($arr['account_id']), intval($primary), @@ -278,6 +273,7 @@ function create_identity($arr) { dbesc($key['prvkey']), dbesc($key['pubkey']), intval($pageflags), + intval($system), intval($expire), dbesc($a->timezone) ); @@ -300,14 +296,14 @@ function create_identity($arr) { // Create a verified hub location pointing to this site. - $r = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_flags, + $r = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_primary, hubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey, hubloc_network ) values ( '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s' )", dbesc($guid), dbesc($sig), dbesc($hash), dbesc($ret['channel']['channel_address'] . '@' . get_app()->get_hostname()), - intval(($primary) ? HUBLOC_FLAGS_PRIMARY : 0), + intval($primary), dbesc(z_root()), dbesc(base64url_encode(rsa_sign(z_root(),$ret['channel']['channel_prvkey']))), dbesc(get_app()->get_hostname()), @@ -320,7 +316,7 @@ function create_identity($arr) { $newuid = $ret['channel']['channel_id']; - $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_guid_sig, xchan_pubkey, xchan_photo_l, xchan_photo_m, xchan_photo_s, xchan_addr, xchan_url, xchan_follow, xchan_connurl, xchan_name, xchan_network, xchan_photo_date, xchan_name_date, xchan_flags ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d)", + $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_guid_sig, xchan_pubkey, xchan_photo_l, xchan_photo_m, xchan_photo_s, xchan_addr, xchan_url, xchan_follow, xchan_connurl, xchan_name, xchan_network, xchan_photo_date, xchan_name_date, xchan_system ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d)", dbesc($hash), dbesc($guid), dbesc($sig), @@ -336,7 +332,7 @@ function create_identity($arr) { dbesc('zot'), dbesc(datetime_convert()), dbesc(datetime_convert()), - intval($xchanflags) + intval($system) ); // Not checking return value. @@ -363,7 +359,7 @@ function create_identity($arr) { |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE; - $r = q("insert into abook ( abook_account, abook_channel, abook_xchan, abook_closeness, abook_created, abook_updated, abook_flags, abook_my_perms ) + $r = q("insert into abook ( abook_account, abook_channel, abook_xchan, abook_closeness, abook_created, abook_updated, abook_self, abook_my_perms ) values ( %d, %d, '%s', %d, '%s', '%s', %d, %d ) ", intval($ret['channel']['channel_account_id']), intval($newuid), @@ -371,7 +367,7 @@ function create_identity($arr) { intval(0), dbesc(datetime_convert()), dbesc(datetime_convert()), - intval(ABOOK_FLAG_SELF), + intval(1), intval($myperms) ); @@ -410,6 +406,11 @@ function create_identity($arr) { } } + if(! $system) { + set_pconfig($ret['channel']['channel_id'],'system','photo_path', '%Y-%m'); + set_pconfig($ret['channel']['channel_id'],'system','attach_path','%Y-%m'); + } + // auto-follow any of the hub's pre-configured channel choices. // Only do this if it's the first channel for this account; // otherwise it could get annoying. Don't make this list too big @@ -426,7 +427,7 @@ function create_identity($arr) { } } - call_hooks('register_account', $newuid); + call_hooks('create_identity', $newuid); proc_run('php','include/directory.php', $ret['channel']['channel_id']); } @@ -536,15 +537,14 @@ function identity_basic_export($channel_id, $items = false) { if($r) $ret['config'] = $r; - $r = q("select type, data from photo where scale = 4 and profile = 1 and uid = %d limit 1", + $r = q("select type, data, os_storage from photo where scale = 4 and profile = 1 and uid = %d limit 1", intval($channel_id) ); if($r) { - $ret['photo'] = array('type' => $r[0]['type'], 'data' => base64url_encode($r[0]['data'])); + $ret['photo'] = array('type' => $r[0]['type'], 'data' => (($r[0]['os_storage']) ? base64url_encode(file_get_contents($r[0]['data'])) : base64url_encode($r[0]['data']))); } - // All other term types will be included in items, if requested. $r = q("select * from term where type in (%d,%d) and uid = %d", @@ -556,13 +556,9 @@ function identity_basic_export($channel_id, $items = false) { $ret['term'] = $r; - // make the obj output match the hubzilla file format - - $datestamp = datetime_convert(); + // add psuedo-column obj_baseurl to aid in relocations - $r = q("select obj.*, term.term as obj_term, term.url as obj_url, term.imgurl as obj_imgurl, '%s' as obj_created, '%s' as obj_edited, '%s' as obj_baseurl from obj left join term on obj_obj = term.term_hash where obj_channel = %d", - dbesc($datestamp), - dbesc($datestamp), + $r = q("select obj.*, '%s' as obj_baseurl from obj where obj_channel = %d", dbesc(z_root()), intval($channel_id) ); @@ -570,7 +566,6 @@ function identity_basic_export($channel_id, $items = false) { if($r) $ret['obj'] = $r; - $r = q("select * from app where app_channel = %d", intval($channel_id) ); @@ -600,6 +595,16 @@ function identity_basic_export($channel_id, $items = false) { foreach($r as $rr) $ret['event_item'][] = encode_item($rr,true); } + + $x = menu_list($channel_id); + if($x) { + $ret['menu'] = array(); + for($y = 0; $y < count($x); $y ++) { + $m = menu_fetch($x[$y]['menu_name'],$channel_id,$ret['channel']['channel_hash']); + if($m) + $ret['menu'][] = menu_element($m); + } + } $x = menu_list($channel_id); if($x) { @@ -611,6 +616,10 @@ function identity_basic_export($channel_id, $items = false) { } } + $addon = array('channel_id' => $channel_id,'data' => $ret); + call_hooks('identity_basic_export',$addon); + $ret = $addon['data']; + if(! $items) return $ret; @@ -633,12 +642,17 @@ function identity_basic_export($channel_id, $items = false) { /** @warning this may run into memory limits on smaller systems */ - /** Don't export linked resource items. we'll have to pull those out separately. */ - $r = q("select * from item where (item_flags & %d) > 0 and not (item_restrict & %d) > 0 and uid = %d and resource_type = '' order by created", - intval(ITEM_WALL), - intval(ITEM_DELETED), - intval($channel_id) + /** export three months of posts. If you want to export and import all posts you have to start with + * the first year and export/import them in ascending order. + * + * Don't export linked resource items. we'll have to pull those out separately. + */ + + $r = q("select * from item where item_wall = 1 and item_deleted = 0 and uid = %d and created > %s - INTERVAL %s and resource_type = '' order by created", + intval($channel_id), + db_utcnow(), + db_quoteinterval('3 MONTH') ); if($r) { $ret['item'] = array(); @@ -652,7 +666,6 @@ function identity_basic_export($channel_id, $items = false) { } - function identity_export_year($channel_id,$year,$month = 0) { if(! $year) @@ -673,9 +686,7 @@ function identity_export_year($channel_id,$year,$month = 0) { else $maxdate = datetime_convert('UTC','UTC',$year+1 . '-01-01 00:00:00'); - $r = q("select * from item where (item_flags & %d) > 0 and (item_restrict & %d) = 0 and uid = %d and created >= '%s' and created < '%s' and resource_type = '' order by created ", - intval(ITEM_WALL), - intval(ITEM_DELETED), + $r = q("select * from item where item_wall = 1 and item_deleted = 0 and uid = %d and created >= '%s' and created < '%s' and resource_type = '' order by created", intval($channel_id), dbesc($mindate), dbesc($maxdate) @@ -689,7 +700,6 @@ function identity_export_year($channel_id,$year,$month = 0) { $ret['item'][] = encode_item($rr,true); } - $r = q("select item_id.*, item.mid from item_id left join item on item_id.iid = item.id where item_id.uid = %d and item.created >= '%s' and item.created < '%s' order by created ", intval($channel_id), @@ -724,11 +734,10 @@ function identity_export_year($channel_id,$year,$month = 0) { */ function profile_load(&$a, $nickname, $profile = '') { - logger('profile_load: ' . $nickname . (($profile) ? ' profile: ' . $profile : '')); +// logger('profile_load: ' . $nickname . (($profile) ? ' profile: ' . $profile : '')); - $user = q("select channel_id from channel where channel_address = '%s' and not ( channel_pageflags & %d ) > 0 limit 1", - dbesc($nickname), - intval(PAGE_REMOVED) + $user = q("select channel_id from channel where channel_address = '%s' and channel_removed = 0 limit 1", + dbesc($nickname) ); if(! $user) { @@ -771,10 +780,9 @@ function profile_load(&$a, $nickname, $profile = '') { if(! $p) { $p = q("SELECT profile.uid AS profile_uid, profile.*, channel.* FROM profile LEFT JOIN channel ON profile.uid = channel.channel_id - WHERE channel.channel_address = '%s' and not ( channel_pageflags & %d )>0 + WHERE channel.channel_address = '%s' and channel_removed = 0 AND profile.is_default = 1 LIMIT 1", - dbesc($nickname), - intval(PAGE_REMOVED) + dbesc($nickname) ); } @@ -989,7 +997,8 @@ function profile_sidebar($profile, $block = 0, $show_connect = true) { $marital = ((x($profile,'marital') == 1) ? t('Status:') : False); $homepage = ((x($profile,'homepage') == 1) ? t('Homepage:') : False); $profile['online'] = (($profile['online_status'] === 'online') ? t('Online Now') : False); - logger('online: ' . $profile['online']); + +// logger('online: ' . $profile['online']); if(! perm_is_allowed($profile['uid'],((is_array($observer)) ? $observer['xchan_hash'] : ''),'view_profile')) { $block = true; @@ -1481,7 +1490,7 @@ function get_default_profile_photo($size = 300) { } /** - * @brief Test whether a given identity is NOT a member of the Red Matrix. + * @brief Test whether a given identity is NOT a member of the Hubzilla. * * @param string $s; * xchan_hash of the identity in question @@ -1492,7 +1501,7 @@ function is_foreigner($s) { } /** - * @brief Test whether a given identity is a member of the Red Matrix. + * @brief Test whether a given identity is a member of the Hubzilla. * * @param string $s; * xchan_hash of the identity in question @@ -1564,9 +1573,8 @@ function get_channel_by_nick($nick) { */ function identity_selector() { if (local_channel()) { - $r = q("select channel.*, xchan.* from channel left join xchan on channel.channel_hash = xchan.xchan_hash where channel.channel_account_id = %d and (channel_pageflags & %d) = 0 order by channel_name ", - intval(get_account_id()), - intval(PAGE_REMOVED) + $r = q("select channel.*, xchan.* from channel left join xchan on channel.channel_hash = xchan.xchan_hash where channel.channel_account_id = %d and channel_removed = 0 order by channel_name ", + intval(get_account_id()) ); if (count($r) > 1) { //$account = get_app()->get_account(); @@ -1662,9 +1670,8 @@ function notifications_on($channel_id,$value) { function get_channel_default_perms($uid) { - $r = q("select abook_my_perms from abook where abook_channel = %d and (abook_flags & %d) > 0 limit 1", - intval($uid), - intval(ABOOK_FLAG_SELF) + $r = q("select abook_my_perms from abook where abook_channel = %d and abook_self = 1 limit 1", + intval($uid) ); if($r) return $r[0]['abook_my_perms']; diff --git a/include/import.php b/include/import.php new file mode 100644 index 000000000..ad8bcd84e --- /dev/null +++ b/include/import.php @@ -0,0 +1,806 @@ +<?php + +require_once('include/menu.php'); + +function import_channel($channel) { + + if(! array_key_exists('channel_system',$channel)) { + $channel['channel_system'] = (($channel['channel_pageflags'] & 0x1000) ? 1 : 0); + $channel['channel_removed'] = (($channel['channel_pageflags'] & 0x8000) ? 1 : 0); + } + + $r = q("select * from channel where (channel_guid = '%s' or channel_hash = '%s' or channel_address = '%s' ) limit 1", + dbesc($channel['channel_guid']), + dbesc($channel['channel_hash']), + dbesc($channel['channel_address']) + ); + + // We should probably also verify the hash + + if($r) { + if($r[0]['channel_guid'] === $channel['channel_guid'] || $r[0]['channel_hash'] === $channel['channel_hash']) { + logger('mod_import: duplicate channel. ', print_r($channel,true)); + notice( t('Cannot create a duplicate channel identifier on this system. Import failed.') . EOL); + return false; + } + else { + // try at most ten times to generate a unique address. + $x = 0; + $found_unique = false; + do { + $tmp = $channel['channel_address'] . mt_rand(1000,9999); + $r = q("select * from channel where channel_address = '%s' limit 1", + dbesc($tmp) + ); + if(! $r) { + $channel['channel_address'] = $tmp; + $found_unique = true; + break; + } + $x ++; + } while ($x < 10); + if(! $found_unique) { + logger('mod_import: duplicate channel. randomisation failed.', print_r($channel,true)); + notice( t('Unable to create a unique channel address. Import failed.') . EOL); + return false; + } + } + } + + unset($channel['channel_id']); + $channel['channel_account_id'] = get_account_id(); + $channel['channel_primary'] = (($seize) ? 1 : 0); + + if($channel['channel_pageflags'] & PAGE_ALLOWCODE) { + if(! is_site_admin()) + $channel['channel_pageflags'] = $channel['channel_pageflags'] ^ PAGE_ALLOWCODE; + } + + dbesc_array($channel); + + $r = dbq("INSERT INTO channel (`" + . implode("`, `", array_keys($channel)) + . "`) VALUES ('" + . implode("', '", array_values($channel)) + . "')" + ); + + if(! $r) { + logger('mod_import: channel clone failed. ', print_r($channel,true)); + notice( t('Channel clone failed. Import failed.') . EOL); + return false; + } + + $r = q("select * from channel where channel_account_id = %d and channel_guid = '%s' limit 1", + intval(get_account_id()), + $channel['channel_guid'] // Already dbesc'd + ); + if(! $r) { + logger('mod_import: channel not found. ', print_r($channel,true)); + notice( t('Cloned channel not found. Import failed.') . EOL); + return false; + } + // reset + $channel = $r[0]; + + set_default_login_identity(get_account_id(),$channel['channel_id'],false); + logger('import step 1'); + $_SESSION['import_step'] = 1; + ref_session_write(session_id(), serialize($_SESSION)); + return $channel; + +} + +function import_config($channel,$configs) { + + if($channel && $configs) { + foreach($configs as $config) { + unset($config['id']); + $config['uid'] = $channel['channel_id']; + dbesc_array($config); + $r = dbq("INSERT INTO pconfig (`" + . implode("`, `", array_keys($config)) + . "`) VALUES ('" + . implode("', '", array_values($config)) + . "')" ); + } + load_pconfig($channel['channel_id']); + } +} + + +function import_profiles($channel,$profiles) { + + if($channel && $profiles) { + foreach($profiles as $profile) { + unset($profile['id']); + $profile['aid'] = get_account_id(); + $profile['uid'] = $channel['channel_id']; + + // we are going to reset all profile photos to the original + // somebody will have to fix this later and put all the applicable photos into the export + + $profile['photo'] = z_root() . '/photo/profile/l/' . $channel['channel_id']; + $profile['thumb'] = z_root() . '/photo/profile/m/' . $channel['channel_id']; + + dbesc_array($profile); + $r = dbq("INSERT INTO profile (`" + . implode("`, `", array_keys($profile)) + . "`) VALUES ('" + . implode("', '", array_values($profile)) + . "')" + ); + } + } +} + + +function import_hublocs($channel,$hublocs,$seize) { + + if($channel && $hublocs) { + foreach($hublocs as $hubloc) { + + $hash = make_xchan_hash($hubloc['hubloc_guid'],$hubloc['hubloc_guid_sig']); + if($hubloc['hubloc_network'] === 'zot' && $hash !== $hubloc['hubloc_hash']) { + logger('forged hubloc: ' . print_r($hubloc,true)); + continue; + } + + if(! array_key_exists('hubloc_primary',$hubloc)) { + $hubloc['hubloc_primary'] = (($hubloc['hubloc_flags'] & 0x0001) ? 1 : 0); + $hubloc['hubloc_orphancheck'] = (($hubloc['hubloc_flags'] & 0x0004) ? 1 : 0); + $hubloc['hubloc_error'] = (($hubloc['hubloc_status'] & 0x0003) ? 1 : 0); + $hubloc['hubloc_deleted'] = (($hubloc['hubloc_flags'] & 0x1000) ? 1 : 0); + } + + $arr = array( + 'guid' => $hubloc['hubloc_guid'], + 'guid_sig' => $hubloc['hubloc_guid_sig'], + 'url' => $hubloc['hubloc_url'], + 'url_sig' => $hubloc['hubloc_url_sig'] + ); + if(($hubloc['hubloc_hash'] === $channel['channel_hash']) && intval($hubloc['hubloc_primary']) && ($seize)) + $hubloc['hubloc_primary'] = 0; + + if(! zot_gethub($arr)) { + unset($hubloc['hubloc_id']); + dbesc_array($hubloc); + + $r = dbq("INSERT INTO hubloc (`" + . implode("`, `", array_keys($hubloc)) + . "`) VALUES ('" + . implode("', '", array_values($hubloc)) + . "')" + ); + } + } + } +} + + + +function import_objs($channel,$objs) { + + if($channel && $objs) { + foreach($objs as $obj) { + + // if it's the old term format - too hard to support + if(! $obj['obj_created']) + continue; + + $baseurl = $obj['obj_baseurl']; + unset($obj['obj_id']); + unset($obj['obj_baseurl']); + + $obj['obj_channel'] = $channel['channel_id']; + + if($baseurl && (strpos($obj['obj_url'],$baseurl . '/thing/') !== false)) { + $obj['obj_url'] = str_replace($baseurl,z_root(),$obj['obj_url']); + } + + if($obj['obj_imgurl']) { + $x = import_xchan_photo($obj['obj_imgurl'],$channel['channel_hash'],true); + $obj['obj_imgurl'] = $x[0]; + } + + dbesc_array($obj); + + $r = dbq("INSERT INTO obj (`" + . implode("`, `", array_keys($obj)) + . "`) VALUES ('" + . implode("', '", array_values($obj)) + . "')" + ); + } + } +} + +function sync_objs($channel,$objs) { + + if($channel && $objs) { + foreach($objs as $obj) { + + if(array_key_exists('obj_deleted',$obj) && $obj['obj_deleted'] && $obj['obj_obj']) { + q("delete from obj where obj_obj = '%s' and obj_channel = %d limit 1", + dbesc($obj['obj_obj']), + intval($channel['channel_id']) + ); + continue; + } + + // if it's the old term format - too hard to support + if(! $obj['obj_created']) + continue; + + $baseurl = $obj['obj_baseurl']; + unset($obj['obj_id']); + unset($obj['obj_baseurl']); + + $obj['obj_channel'] = $channel['channel_id']; + + if($baseurl && (strpos($obj['obj_url'],$baseurl . '/thing/') !== false)) { + $obj['obj_url'] = str_replace($baseurl,z_root(),$obj['obj_url']); + } + + $exists = false; + + $x = q("select * from obj where obj_obj = '%s' and obj_channel = %d limit 1", + dbesc($obj['obj_obj']), + intval($channel['channel_id']) + ); + if($x) { + if($x[0]['obj_edited'] >= $obj['obj_edited']) + continue; + + $exists = true; + } + + if($obj['obj_imgurl']) { + $x = import_xchan_photo($obj['obj_imgurl'],$channel['channel_hash'],true); + $obj['obj_imgurl'] = $x[0]; + } + + $hash = $obj['obj_obj']; + + if($exists) { + unset($obj['obj_obj']); + foreach($obj as $k => $v) { + $r = q("UPDATE obj SET `%s` = '%s' WHERE obj_obj = '%s' AND obj_channel = %d", + dbesc($k), + dbesc($v), + dbesc($hash), + intval($channel['channel_id']) + ); + } + } + else { + + dbesc_array($obj); + + $r = dbq("INSERT INTO obj (`" + . implode("`, `", array_keys($obj)) + . "`) VALUES ('" + . implode("', '", array_values($obj)) + . "')" + ); + } + } + } +} + + + + + +function import_apps($channel,$apps) { + + if($channel && $apps) { + foreach($apps as $app) { + + unset($app['id']); + unset($app['app_channel']); + + $app['app_channel'] = $channel['channel_id']; + + if($app['app_photo']) { + $x = import_xchan_photo($app['app_photo'],$channel['channel_hash'],true); + $app['app_photo'] = $x[0]; + } + + dbesc_array($app); + $r = dbq("INSERT INTO app (`" + . implode("`, `", array_keys($app)) + . "`) VALUES ('" + . implode("', '", array_values($app)) + . "')" + ); + } + } +} + + + +function sync_apps($channel,$apps) { + + if($channel && $apps) { + foreach($apps as $app) { + + if(array_key_exists('app_deleted',$app) && $app['app_deleted'] && $app['app_id']) { + q("delete from app where app_id = '%s' and app_channel = %d limit 1", + dbesc($app['app_id']), + intval($channel['channel_id']) + ); + continue; + } + + unset($app['id']); + unset($app['app_channel']); + + if(! $app['app_created'] || $app['app_created'] === NULL_DATE) + $app['app_created'] = datetime_convert(); + if(! $app['app_edited'] || $app['app_edited'] === NULL_DATE) + $app['app_edited'] = datetime_convert(); + + $app['app_channel'] = $channel['channel_id']; + + if($app['app_photo']) { + $x = import_xchan_photo($app['app_photo'],$channel['channel_hash'],true); + $app['app_photo'] = $x[0]; + } + + $exists = false; + + $x = q("select * from app where app_id = '%s' and app_channel = %d limit 1", + dbesc($app['app_id']), + intval($channel['channel_id']) + ); + if($x) { + if($x[0]['app_edited'] >= $app['app_edited']) + continue; + $exists = true; + } + $hash = $app['app_id']; + + if($exists) { + unset($app['app_id']); + foreach($app as $k => $v) { + $r = q("UPDATE app SET `%s` = '%s' WHERE app_id = '%s' AND app_channel = %d", + dbesc($k), + dbesc($v), + dbesc($hash), + intval($channel['channel_id']) + ); + } + } + else { + dbesc_array($app); + $r = dbq("INSERT INTO app (`" + . implode("`, `", array_keys($app)) + . "`) VALUES ('" + . implode("', '", array_values($app)) + . "')" + ); + } + } + } +} + + + +function import_chatrooms($channel,$chatrooms) { + + if($channel && $chatrooms) { + foreach($chatrooms as $chatroom) { + + if(! $chatroom['cr_name']) + continue; + + unset($chatroom['cr_id']); + unset($chatroom['cr_aid']); + unset($chatroom['cr_uid']); + + $chatroom['cr_aid'] = $channel['channel_account_id']; + $chatroom['cr_uid'] = $channel['channel_id']; + + dbesc_array($chatroom); + $r = dbq("INSERT INTO chatroom (`" + . implode("`, `", array_keys($chatroom)) + . "`) VALUES ('" + . implode("', '", array_values($chatroom)) + . "')" + ); + } + } +} + + + +function sync_chatrooms($channel,$chatrooms) { + + if($channel && $chatrooms) { + foreach($chatrooms as $chatroom) { + + if(! $chatroom['cr_name']) + continue; + + if(array_key_exists('cr_deleted',$chatroom) && $chatroom['cr_deleted']) { + q("delete from chatroom where cr_name = '%s' and cr_uid = %d limit 1", + dbesc($chatroom['cr_name']), + intval($channel['channel_id']) + ); + continue; + } + + + unset($chatroom['cr_id']); + unset($chatroom['cr_aid']); + unset($chatroom['cr_uid']); + + if(! $chatroom['cr_created'] || $chatroom['cr_created'] === NULL_DATE) + $chatroom['cr_created'] = datetime_convert(); + if(! $chatroom['cr_edited'] || $chatroom['cr_edited'] === NULL_DATE) + $chatroom['cr_edited'] = datetime_convert(); + + $chatroom['cr_aid'] = $channel['channel_account_id']; + $chatroom['cr_uid'] = $channel['channel_id']; + + $exists = false; + + $x = q("select * from chatroom where cr_name = '%s' and cr_uid = %d limit 1", + dbesc($chatroom['cr_name']), + intval($channel['channel_id']) + ); + if($x) { + if($x[0]['cr_edited'] >= $chatroom['cr_edited']) + continue; + $exists = true; + } + $name = $chatroom['cr_name']; + + if($exists) { + foreach($chatroom as $k => $v) { + $r = q("UPDATE chatroom SET `%s` = '%s' WHERE cr_name = '%s' AND cr_uid = %d", + dbesc($k), + dbesc($v), + dbesc($name), + intval($channel['channel_id']) + ); + } + } + else { + dbesc_array($chatroom); + $r = dbq("INSERT INTO chatroom (`" + . implode("`, `", array_keys($chatroom)) + . "`) VALUES ('" + . implode("', '", array_values($chatroom)) + . "')" + ); + } + } + } +} + + + +function import_items($channel,$items) { + + if($channel && $items) { + $allow_code = false; + $r = q("select account_id, account_roles, channel_pageflags from account left join channel on channel_account_id = account_id + where channel_id = %d limit 1", + intval($channel['channel_id']) + ); + if($r) { + if(($r[0]['account_roles'] & ACCOUNT_ROLE_ALLOWCODE) || ($r[0]['channel_pageflags'] & PAGE_ALLOWCODE)) { + $allow_code = true; + } + } + + foreach($items as $i) { + $item = get_item_elements($i,$allow_code); + if(! $item) + continue; + + $r = q("select id, edited from item where mid = '%s' and uid = %d limit 1", + dbesc($item['mid']), + intval($channel['channel_id']) + ); + if($r) { + if($item['edited'] > $r[0]['edited']) { + $item['id'] = $r[0]['id']; + $item['uid'] = $channel['channel_id']; + item_store_update($item); + continue; + } + } + else { + $item['aid'] = $channel['channel_account_id']; + $item['uid'] = $channel['channel_id']; + $item_result = item_store($item); + } + + } + } +} + + +function sync_items($channel,$items) { + import_items($channel,$items); +} + + + +function import_item_ids($channel,$itemids) { + if($channel && $itemids) { + foreach($itemids as $i) { + $r = q("select id from item where mid = '%s' and uid = %d limit 1", + dbesc($i['mid']), + intval($channel['channel_id']) + ); + if(! $r) + continue; + $z = q("select * from item_id where service = '%s' and sid = '%s' and iid = %d and uid = %d limit 1", + dbesc($i['service']), + dbesc($i['sid']), + intval($r[0]['id']), + intval($channel['channel_id']) + ); + if(! $z) { + q("insert into item_id (iid,uid,sid,service) values(%d,%d,'%s','%s')", + intval($r[0]['id']), + intval($channel['channel_id']), + dbesc($i['sid']), + dbesc($i['service']) + ); + } + } + } +} + +function import_events($channel,$events) { + + if($channel && $events) { + foreach($events as $event) { + unset($event['id']); + $event['aid'] = $channel['channel_account_id']; + $event['uid'] = $channel['channel_id']; + + dbesc_array($event); + $r = dbq("INSERT INTO event (`" + . implode("`, `", array_keys($event)) + . "`) VALUES ('" + . implode("', '", array_values($event)) + . "')" + ); + } + } +} + + +function sync_events($channel,$events) { + + if($channel && $events) { + foreach($events as $event) { + + if((! $event['event_hash']) || (! $event['start'])) + continue; + + if($event['event_deleted']) { + $r = q("delete from event where event_hash = '%s' and uid = %d limit 1", + dbesc($event['event_hash']), + intval($channel['channel_id']) + ); + continue; + } + + unset($event['id']); + $event['aid'] = $channel['channel_account_id']; + $event['uid'] = $channel['channel_id']; + + $exists = false; + + $x = q("select * from event where event_hash = '%s' and uid = %d limit 1", + dbesc($event['event_hash']), + intval($channel['channel_id']) + ); + if($x) { + if($x[0]['edited'] >= $event['edited']) + continue; + $exists = true; + } + + if($exists) { + foreach($event as $k => $v) { + $r = q("UPDATE event SET `%s` = '%s' WHERE event_hash = '%s' AND uid = %d", + dbesc($k), + dbesc($v), + dbesc($event['event_hash']), + intval($channel['channel_id']) + ); + } + } + else { + dbesc_array($event); + $r = dbq("INSERT INTO event (`" + . implode("`, `", array_keys($event)) + . "`) VALUES ('" + . implode("', '", array_values($event)) + . "')" + ); + } + } + } +} + + +function import_menus($channel,$menus) { + + if($channel && $menus) { + foreach($menus as $menu) { + $m = array(); + $m['menu_channel_id'] = $channel['channel_id']; + $m['menu_name'] = $menu['pagetitle']; + $m['menu_desc'] = $menu['desc']; + if($menu['created']) + $m['menu_created'] = datetime_convert($menu['created']); + if($menu['edited']) + $m['menu_edited'] = datetime_convert($menu['edited']); + + $m['menu_flags'] = 0; + if($menu['flags']) { + if(in_array('bookmark',$menu['flags'])) + $m['menu_flags'] |= MENU_BOOKMARK; + if(in_array('system',$menu['flags'])) + $m['menu_flags'] |= MENU_SYSTEM; + + } + + $menu_id = menu_create($m); + + if($menu_id) { + if(is_array($menu['items'])) { + foreach($menu['items'] as $it) { + $mitem = array(); + + $mitem['mitem_link'] = str_replace('[baseurl]',z_root(),$it['link']); + $mitem['mitem_desc'] = escape_tags($it['desc']); + $mitem['mitem_order'] = intval($it['order']); + if(is_array($it['flags'])) { + $mitem['mitem_flags'] = 0; + if(in_array('zid',$it['flags'])) + $mitem['mitem_flags'] |= MENU_ITEM_ZID; + if(in_array('new-window',$it['flags'])) + $mitem['mitem_flags'] |= MENU_ITEM_NEWWIN; + if(in_array('chatroom',$it['flags'])) + $mitem['mitem_flags'] |= MENU_ITEM_CHATROOM; + } + menu_add_item($menu_id,$channel['channel_id'],$mitem); + } + } + } + } + } +} + + +function sync_menus($channel,$menus) { + + if($channel && $menus) { + foreach($menus as $menu) { + $m = array(); + $m['menu_channel_id'] = $channel['channel_id']; + $m['menu_name'] = $menu['pagetitle']; + $m['menu_desc'] = $menu['desc']; + if($menu['created']) + $m['menu_created'] = datetime_convert($menu['created']); + if($menu['edited']) + $m['menu_edited'] = datetime_convert($menu['edited']); + + $m['menu_flags'] = 0; + if($menu['flags']) { + if(in_array('bookmark',$menu['flags'])) + $m['menu_flags'] |= MENU_BOOKMARK; + if(in_array('system',$menu['flags'])) + $m['menu_flags'] |= MENU_SYSTEM; + + } + + $editing = false; + + $r = q("select * from menu where menu_name = '%s' and menu_channel_id = %d limit 1", + dbesc($m['menu_name']), + intval($channel['channel_id']) + ); + if($r) { + if($r[0]['menu_edited'] >= $m['menu_edited']) + continue; + if($menu['menu_deleted']) { + menu_delete_id($r[0]['menu_id'],$channel['channel_id']); + continue; + } + $menu_id = $r[0]['menu_id']; + $m['menu_id'] = $r[0]['menu_id']; + $x = menu_edit($m); + if(! $x) + continue; + $editing = true; + } + if(! $editing) { + $menu_id = menu_create($m); + } + if($menu_id) { + if($editing) { + // don't try syncing - just delete all the entries and start over + q("delete from menu_item where mitem_menu_id = %d", + intval($menu_id) + ); + } + + if(is_array($menu['items'])) { + foreach($menu['items'] as $it) { + $mitem = array(); + + $mitem['mitem_link'] = str_replace('[baseurl]',z_root(),$it['link']); + $mitem['mitem_desc'] = escape_tags($it['desc']); + $mitem['mitem_order'] = intval($it['order']); + if(is_array($it['flags'])) { + $mitem['mitem_flags'] = 0; + if(in_array('zid',$it['flags'])) + $mitem['mitem_flags'] |= MENU_ITEM_ZID; + if(in_array('new-window',$it['flags'])) + $mitem['mitem_flags'] |= MENU_ITEM_NEWWIN; + if(in_array('chatroom',$it['flags'])) + $mitem['mitem_flags'] |= MENU_ITEM_CHATROOM; + } + menu_add_item($menu_id,$channel['channel_id'],$mitem); + } + } + } + } + } +} + + + +function import_likes($channel,$likes) { + if($channel && $likes) { + foreach($likes as $like) { + if($like['deleted']) { + q("delete from likes where liker = '%s' and likee = '%s' and verb = '%s' and target_type = '%s' and target_id = '%s'", + dbesc($like['liker']), + dbesc($like['likee']), + dbesc($like['verb']), + dbesc($like['target_type']), + dbesc($like['target_id']) + ); + continue; + } + + unset($like['id']); + unset($like['iid']); + $like['channel_id'] = $channel['channel_id']; + $r = q("select * from likes where liker = '%s' and likee = '%s' and verb = '%s' and target_type = '%s' and target_id = '%s' and i_mid = '%s'", + dbesc($like['liker']), + dbesc($like['likee']), + dbesc($like['verb']), + dbesc($like['target_type']), + dbesc($like['target_id']), + dbesc($like['i_mid']) + ); + if($r) + continue; + + dbesc_array($config); + $r = dbq("INSERT INTO likes (`" + . implode("`, `", array_keys($like)) + . "`) VALUES ('" + . implode("', '", array_values($like)) + . "')" ); + } + } +} + + + + + diff --git a/include/importdoc.php b/include/importdoc.php new file mode 100755 index 000000000..10f868697 --- /dev/null +++ b/include/importdoc.php @@ -0,0 +1,41 @@ +<?php + + + +require_once('include/cli_startup.php'); + + +function importdoc_run($argv, $argc){ + + cli_startup(); + + require_once('mod/help.php'); + + + update_docs_dir('doc/*'); + +} +if (array_search(__file__,get_included_files())===0){ + importdoc_run($argv,$argc); + killme(); +} + +function update_docs_dir($s) { + $f = basename($s); + $d = dirname($s); + if($s === 'doc/html') + return; + $files = glob("$d/$f"); + if($files) { + foreach($files as $fi) { + if($fi === 'doc/html') + continue; + if(is_dir($fi)) + update_docs_dir("$fi/*"); + else + store_doc_file($fi); + } + } +} + + diff --git a/include/items.php b/include/items.php index eed9dabb2..e7cc02579 100755 --- a/include/items.php +++ b/include/items.php @@ -42,9 +42,8 @@ function collect_recipients($item, &$private_envelope) { // as that would allow the denied person to see the post by logging out. if((! $item['allow_cid']) && (! $item['allow_gid'])) { - $r = q("select * from abook where abook_channel = %d and not (abook_flags & %d)>0 ", - intval($item['uid']), - intval(ABOOK_FLAG_SELF|ABOOK_FLAG_PENDING|ABOOK_FLAG_ARCHIVED) + $r = q("select * from abook where abook_channel = %d and abook_self = 0 and abook_pending = 0 and abook_archived = 0 ", + intval($item['uid']) ); if($r) { @@ -82,9 +81,8 @@ function collect_recipients($item, &$private_envelope) { //$sys = get_sys_channel(); if(array_key_exists('public_policy',$item) && $item['public_policy'] !== 'self') { - $r = q("select abook_xchan, xchan_network from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and not (abook_flags & %d)>0 ", - intval($item['uid']), - intval(ABOOK_FLAG_SELF|ABOOK_FLAG_PENDING|ABOOK_FLAG_ARCHIVED) + $r = q("select abook_xchan, xchan_network from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 and abook_pending = 0 and abook_archived = 0 ", + intval($item['uid']) ); if($r) { @@ -192,20 +190,30 @@ function comments_are_now_closed($item) { return false; } +function item_normal() { + return " and item.item_hidden = 0 and item.item_type = 0 and item.item_deleted = 0 + and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0 + and item.item_blocked = 0 "; +} + /** * @brief * * This is a compatibility function primarily for plugins, because - * in future hubzilla (and later) DB schemas the definition of a - * normal item gets a bit more complicated. + * in earlier DB schemas this was a much simpler single integer compare * */ function is_item_normal($item) { - return((intval($item['item_restrict'])) ? false : true); -} + if(intval($item['item_hidden']) || intval($item['item_type']) || intval($item['item_deleted']) + || intval($item['item_unpublished']) || intval($item['item_delayed']) || intval($item['item_pending_remove']) + || intval($item['item_blocked'])) + return false; + + return true; +} /** * @brief @@ -264,6 +272,8 @@ function can_comment_on_post($observer_xchan, $item) { } if(strstr($item['comment_policy'],'network:') && strstr($item['comment_policy'],'red')) return true; + if(strstr($item['comment_policy'],'network:') && strstr($item['comment_policy'],'diaspora')) + return true; if(strstr($item['comment_policy'],'site:') && strstr($item['comment_policy'],get_app()->get_hostname())) return true; @@ -396,12 +406,12 @@ function post_activity_item($arr) { if((($arr['parent']) && $arr['parent'] != $arr['id']) || (($arr['parent_mid']) && $arr['parent_mid'] != $arr['mid'])) $is_comment = true; - if(! x($arr,'item_flags')) { - if($is_comment) - $arr['item_flags'] = ITEM_ORIGIN; - else - $arr['item_flags'] = ITEM_ORIGIN | ITEM_WALL | ITEM_THREAD_TOP; - } + if(! array_key_exists('item_origin',$arr)) + $arr['item_origin'] = 1; + if(! array_key_exists('item_wall',$arr) && (! $is_comment)) + $arr['item_wall'] = 1; + if(! array_key_exists('item_thread_top',$arr) && (! $is_comment)) + $arr['item_thread_top'] = 1; $channel = get_app()->get_channel(); $observer = get_app()->get_observer(); @@ -428,17 +438,9 @@ function post_activity_item($arr) { if($channel) { if($channel['channel_hash'] === $arr['author_xchan']) { $arr['sig'] = base64url_encode(rsa_sign($arr['body'],$channel['channel_prvkey'])); - $arr['item_flags'] = $arr['item_flags'] | ITEM_VERIFIED; + $arr['item_verified'] = 1; } } - - logger('Encrypting local storage'); - $key = get_config('system','pubkey'); - $arr['item_flags'] = $arr['item_flags'] | ITEM_OBSCURED; - if($arr['title']) - $arr['title'] = json_encode(crypto_encapsulate($arr['title'],$key)); - if($arr['body']) - $arr['body'] = json_encode(crypto_encapsulate($arr['body'],$key)); } $arr['mid'] = ((x($arr,'mid')) ? $arr['mid'] : item_message_id()); @@ -460,7 +462,7 @@ function post_activity_item($arr) { $arr['comment_policy'] = map_scope($channel['channel_w_comment']); - if ((! $arr['plink']) && ($arr['item_flags'] & ITEM_THREAD_TOP)) { + if ((! $arr['plink']) && (intval($arr['item_thread_top']))) { $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid']; } @@ -495,6 +497,32 @@ function post_activity_item($arr) { return $ret; } + +function validate_item_elements($message,$arr) { + + $result = array('success' => false); + + if(! array_key_exists('created',$arr)) + $result['message'] = 'missing created, possible author/owner lookup failure'; + + if((! $arr['mid']) || (! $arr['parent_mid'])) + $result['message'] = 'missing message-id or parent message-id'; + + if(array_key_exists('flags',$message) && in_array('relay',$message['flags']) && $arr['mid'] === $arr['parent_mid']) + $result['message'] = 'relay set on top level post'; + + if(! $result['message']) + $result['success'] = true; + + return $result; + +} + + + + + + /** * @brief Generate an Atom feed. * @@ -807,7 +835,6 @@ function title_is_body($title, $body) { function get_item_elements($x,$allow_code = false) { - $arr = array(); if($allow_code) @@ -874,7 +901,8 @@ function get_item_elements($x,$allow_code = false) { if(array_key_exists('diaspora_signature',$x) && is_array($x['diaspora_signature'])) $x['diaspora_signature'] = json_encode($x['diaspora_signature']); - $arr['diaspora_meta'] = (($x['diaspora_signature']) ? json_encode(crypto_encapsulate($x['diaspora_signature'],$key)) : ''); + $arr['diaspora_meta'] = (($x['diaspora_signature']) ? $x['diaspora_signature'] : ''); + $arr['object'] = activity_sanitise($x['object']); $arr['target'] = activity_sanitise($x['target']); @@ -886,11 +914,12 @@ function get_item_elements($x,$allow_code = false) { $arr['item_flags'] = 0; if(array_key_exists('flags',$x) && in_array('consensus',$x['flags'])) - $arr['item_flags'] |= ITEM_CONSENSUS; + $arr['item_consensus'] = 1; + if(array_key_exists('flags',$x) && in_array('deleted',$x['flags'])) - $arr['item_restrict'] |= ITEM_DELETED; + $arr['item_deleted'] = 1; if(array_key_exists('flags',$x) && in_array('hidden',$x['flags'])) - $arr['item_restrict'] |= ITEM_HIDDEN; + $arr['item_hidden'] = 1; // Here's the deal - the site might be down or whatever but if there's a new person you've never // seen before sending stuff to your stream, we MUST be able to look them up and import their data from their @@ -918,26 +947,13 @@ function get_item_elements($x,$allow_code = false) { dbesc($arr['author_xchan']) ); if($r && rsa_verify($x['body'],base64url_decode($arr['sig']),$r[0]['xchan_pubkey'])) - $arr['item_flags'] |= ITEM_VERIFIED; + $arr['item_verified'] = 1; else logger('get_item_elements: message verification failed.'); } - // if it's a private post, encrypt it in the DB. - // We have to do that here because we need to cleanse the input and prevent bad stuff from getting in, - // and we need plaintext to do that. - - - if(intval($arr['item_private'])) { - $arr['item_flags'] = $arr['item_flags'] | ITEM_OBSCURED; - if($arr['title']) - $arr['title'] = json_encode(crypto_encapsulate($arr['title'],$key)); - if($arr['body']) - $arr['body'] = json_encode(crypto_encapsulate($arr['body'],$key)); - } - - if(array_key_exists('revision',$x)) { + // extended export encoding $arr['revision'] = $x['revision']; @@ -950,66 +966,77 @@ function get_item_elements($x,$allow_code = false) { $arr['resource_id'] = $x['resource_id']; $arr['resource_type'] = $x['resource_type']; $arr['attach'] = $x['attach']; + $arr['item_origin'] = $x['item_origin']; + $arr['item_unseen'] = $x['item_unseen']; + $arr['item_starred'] = $x['item_starred']; + $arr['item_uplink'] = $x['item_uplink']; + $arr['item_consensus'] = $x['item_consensus']; + $arr['item_wall'] = $x['item_wall']; + $arr['item_thread_top'] = $x['item_thread_top']; + $arr['item_notshown'] = $x['item_notshown']; + $arr['item_nsfw'] = $x['item_nsfw']; + // local only $arr['item_relay'] = $x['item_relay']; + $arr['item_mentionsme'] = $x['item_mentionsme']; + $arr['item_nocomment'] = $x['item_nocomment']; + // local only $arr['item_obscured'] = $x['item_obscured']; + // local only $arr['item_verified'] = $x['item_verified']; + $arr['item_retained'] = $x['item_retained']; + $arr['item_rss'] = $x['item_rss']; + $arr['item_deleted'] = $x['item_deleted']; + $arr['item_type'] = $x['item_type']; + $arr['item_hidden'] = $x['item_hidden']; + $arr['item_unpublished'] = $x['item_unpublished']; + $arr['item_delayed'] = $x['item_delayed']; + $arr['item_pending_remove'] = $x['item_pending_remove']; + $arr['item_blocked'] = $x['item_blocked']; + if(array_key_exists('item_flags',$x)) { + if($x['item_flags'] & 0x0004) + $arr['item_starred'] = 1; + if($x['item_flags'] & 0x0008) + $arr['item_uplink'] = 1; + if($x['item_flags'] & 0x0010) + $arr['item_consensus'] = 1; + if($x['item_flags'] & 0x0020) + $arr['item_wall'] = 1; + if($x['item_flags'] & 0x0040) + $arr['item_thread_top'] = 1; + if($x['item_flags'] & 0x0080) + $arr['item_notshown'] = 1; + if($x['item_flags'] & 0x0100) + $arr['item_nsfw'] = 1; + if($x['item_flags'] & 0x0400) + $arr['item_mentionsme'] = 1; + if($x['item_flags'] & 0x0800) + $arr['item_nocomment'] = 1; + if($x['item_flags'] & 0x4000) + $arr['item_retained'] = 1; + if($x['item_flags'] & 0x8000) + $arr['item_rss'] = 1; - if(! array_key_exists('item_origin',$x)) { - $arr['item_restrict'] = $x['item_restrict']; - $arr['item_flags'] = $x['item_flags']; } - - if(array_key_exists('item_origin',$x) && intval($x['item_origin'])) - $arr['item_flags'] |= ITEM_ORIGIN; - if(array_key_exists('item_unseen',$x) && intval($x['item_unseen'])) - $arr['item_flags'] |= ITEM_UNSEEN; - if(array_key_exists('item_starred',$x) && intval($x['item_starred'])) - $arr['item_flags'] |= ITEM_STARRED; - if(array_key_exists('item_uplink',$x) && intval($x['item_uplink'])) - $arr['item_flags'] |= ITEM_UPLINK; - if(array_key_exists('item_consensus',$x) && intval($x['item_consensus'])) - $arr['item_flags'] |= ITEM_CONSENSUS; - if(array_key_exists('item_wall',$x) && intval($x['item_wall'])) - $arr['item_flags'] |= ITEM_WALL; - if(array_key_exists('item_thread_top',$x) && intval($x['item_thread_top'])) - $arr['item_flags'] |= ITEM_THREAD_TOP; - if(array_key_exists('item_notshown',$x) && intval($x['item_notshown'])) - $arr['item_flags'] |= ITEM_NOTSHOWN; - if(array_key_exists('item_nsfw',$x) && intval($x['item_nsfw'])) - $arr['item_flags'] |= ITEM_NSFW; - if(array_key_exists('item_mentionsme',$x) && intval($x['item_mentionsme'])) - $arr['item_flags'] |= ITEM_MENTIONSME; - if(array_key_exists('item_nocomment',$x) && intval($x['item_nocomment'])) - $arr['item_flags'] |= ITEM_NOCOMMENT; - if(array_key_exists('item_retained',$x) && intval($x['item_retained'])) - $arr['item_flags'] |= ITEM_RETAINED; - if(array_key_exists('item_rss',$x) && intval($x['item_rss'])) - $arr['item_flags'] |= ITEM_RSS; - - - if(array_key_exists('item_deleted',$x)&& intval($x['item_deleted'])) - $arr['item_restrict'] |= ITEM_DELETED; - if(array_key_exists('item_unpublished',$x)&& intval($x['item_unpublished'])) - $arr['item_restrict'] |= ITEM_UNPUBLISHED; - if(array_key_exists('item_delayed',$x)&& intval($x['item_delayed'])) - $arr['item_restrict'] |= ITEM_DELAYED_PUBLISH; - if(array_key_exists('item_pending_remove',$x)&& intval($x['item_pending_remove'])) - $arr['item_restrict'] |= ITEM_PENDING_REMOVE; - if(array_key_exists('item_type',$x)) { - switch(intval($x['item_type'])) { - case 1: - $arr['item_restrict'] |= ITEM_BUILDBLOCK; - break; - case 2: - $arr['item_restrict'] |= ITEM_PDL; - break; - case 3: - $arr['item_restrict'] |= ITEM_WEBPAGE; - break; - case 4: - $arr['item_restrict'] |= ITEM_BUG; - break; - case 0: - default: - break; - } + if(array_key_exists('item_restrict',$x)) { + if($x['item_restrict'] & 0x0001) + $arr['item_hidden'] = 1; + if($x['item_restrict'] & 0x0002) + $arr['item_blocked'] = 1; + if($x['item_restrict'] & 0x0010) + $arr['item_deleted'] = 1; + if($x['item_restrict'] & 0x0020) + $arr['item_unpublished'] = 1; + if($x['item_restrict'] & 0x0040) + $arr['item_type'] = ITEM_TYPE_WEBPAGE; + if($x['item_restrict'] & 0x0080) + $arr['item_delayed'] = 1; + if($x['item_restrict'] & 0x0100) + $arr['item_type'] = ITEM_TYPE_BLOCK; + if($x['item_restrict'] & 0x0200) + $arr['item_type'] = ITEM_TYPE_PDL; + if($x['item_restrict'] & 0x0400) + $arr['item_type'] = ITEM_TYPE_BUG; + if($x['item_restrict'] & 0x0800) + $arr['item_pending_remove'] = 1; + if($x['item_restrict'] & 0x1000) + $arr['item_type'] = ITEM_TYPE_DOC; } } @@ -1104,7 +1131,7 @@ function import_author_rss($x) { if($r && $x['photo']) { - $photos = import_profile_photo($x['photo']['src'],$x['url']); + $photos = import_xchan_photo($x['photo']['src'],$x['url']); if($photos) { /** @bug $arr is undefined in this SQL query */ @@ -1149,7 +1176,7 @@ function import_author_unknown($x) { ); if($r && $x['photo']) { - $photos = import_profile_photo($x['photo']['src'],$x['url']); + $photos = import_xchan_photo($x['photo']['src'],$x['url']); if($photos) { /** @bug $arr is undefined in this SQL query */ @@ -1193,7 +1220,7 @@ function encode_item($item,$mirror = false) { $key = get_config('system','prvkey'); - if(array_key_exists('item_flags',$item) && ($item['item_flags'] & ITEM_OBSCURED)) { + if(array_key_exists('item_obscured',$item) && intval($item['item_obscured'])) { if($item['title']) $item['title'] = crypto_unencapsulate(json_decode_plus($item['title']),$key); if($item['body']) @@ -1216,67 +1243,30 @@ function encode_item($item,$mirror = false) { $x['postopts'] = $item['postopts']; $x['resource_id'] = $item['resource_id']; $x['resource_type'] = $item['resource_type']; - $x['item_restrict'] = $item['item_restrict']; - $x['item_flags'] = $item['item_flags']; - $x['item_unseen'] = $item['item_unseen']; $x['attach'] = $item['attach']; - if(array_key_exists('item_starred',$item) && intval($item['item_starred'])) - $x['item_flags'] |= ITEM_STARRED; - if(array_key_exists('item_uplink',$item) && intval($item['item_uplink'])) - $x['item_flags'] |= ITEM_UPLINK; - if(array_key_exists('item_consensus',$item) && intval($item['item_consensus'])) - $x['item_flags'] |= ITEM_CONSENSUS; - if(array_key_exists('item_wall',$item) && intval($item['item_wall'])) - $x['item_flags'] |= ITEM_WALL; - if(array_key_exists('item_thread_top',$item) && intval($item['item_thread_top'])) - $x['item_flags'] |= ITEM_THREAD_TOP; - if(array_key_exists('item_notshown',$item) && intval($item['item_notshown'])) - $x['item_flags'] |= ITEM_NOTSHOWN; - if(array_key_exists('item_nsfw',$item) && intval($item['item_nsfw'])) - $x['item_flags'] |= ITEM_NSFW; - if(array_key_exists('item_mentionsme',$item) && intval($item['item_mentionsme'])) - $x['item_flags'] |= ITEM_MENTIONSME; - if(array_key_exists('item_nocomment',$item) && intval($item['item_nocomment'])) - $x['item_flags'] |= ITEM_NOCOMMENT; - if(array_key_exists('item_retained',$item) && intval($item['item_retained'])) - $x['item_flags'] |= ITEM_RETAINED; - if(array_key_exists('item_rss',$item) && intval($item['item_rss'])) - $x['item_flags'] |= ITEM_RSS; - if(array_key_exists('item_deleted',$item) && intval($item['item_deleted'])) - $x['item_restrict'] |= ITEM_DELETED; - if(array_key_exists('item_hidden',$item) && intval($item['item_hidden'])) - $x['item_restrict'] |= ITEM_HIDDEN; - if(array_key_exists('item_unpublished',$item) && intval($item['item_unpublished'])) - $x['item_restrict'] |= ITEM_UNPUBLISHED; - if(array_key_exists('item_delayed',$item) && intval($item['item_delayed'])) - $x['item_restrict'] |= ITEM_DELAYED_PUBLISH; - if(array_key_exists('item_pending_remove',$item) && intval($item['item_pending_remove'])) - $x['item_restrict'] |= ITEM_PENDING_REMOVE; - if(array_key_exists('item_blocked',$item) && intval($item['item_blocked'])) - $x['item_flags'] |= ITEM_BLOCKED; - if(array_key_exists('item_',$item) && intval($item['item_'])) - $x['item_flags'] |= ITEM_; - if(array_key_exists('item_type',$item) && intval($item['item_type'])) { - switch(intval($item['item_type'])) { - case 1: - $x['item_restrict'] |= ITEM_BUILDBLOCK; - break; - case 2: - $x['item_restrict'] |= ITEM_PDL; - break; - case 3: - $x['item_restrict'] |= ITEM_WEBPAGE; - break; - case 4: - $x['item_restrict'] |= ITEM_BUG; - break; - case 5: - $x['item_restrict'] |= ITEM_DOC; - break; - default: - break; - } - } + $x['item_origin'] = $item['item_origin']; + $x['item_unseen'] = $item['item_unseen']; + $x['item_starred'] = $item['item_starred']; + $x['item_uplink'] = $item['item_uplink']; + $x['item_consensus'] = $item['item_consensus']; + $x['item_wall'] = $item['item_wall']; + $x['item_thread_top'] = $item['item_thread_top']; + $x['item_notshown'] = $item['item_notshown']; + $x['item_nsfw'] = $item['item_nsfw']; + $x['item_relay'] = $item['item_relay']; + $x['item_mentionsme'] = $item['item_mentionsme']; + $x['item_nocomment'] = $item['item_nocomment']; + $x['item_obscured'] = $item['item_obscured']; + $x['item_verified'] = $item['item_verified']; + $x['item_retained'] = $item['item_retained']; + $x['item_rss'] = $item['item_rss']; + $x['item_deleted'] = $item['item_deleted']; + $x['item_type'] = $item['item_type']; + $x['item_hidden'] = $item['item_hidden']; + $x['item_unpublished'] = $item['item_unpublished']; + $x['item_delayed'] = $item['item_delayed']; + $x['item_pending_remove'] = $item['item_pending_remove']; + $x['item_blocked'] = $item['item_blocked']; } @@ -1317,7 +1307,7 @@ function encode_item($item,$mirror = false) { $x['public_scope'] = $scope; - if($item['item_flags'] & ITEM_NOCOMMENT) + if($item['item_nocomment']) $x['comment_scope'] = 'none'; else $x['comment_scope'] = $c_scope; @@ -1325,9 +1315,17 @@ function encode_item($item,$mirror = false) { if($item['term']) $x['tags'] = encode_item_terms($item['term'],$mirror); - if($item['diaspora_meta']) - $x['diaspora_signature'] = crypto_unencapsulate(json_decode($item['diaspora_meta'],true),$key); - + if($item['diaspora_meta']) { + $z = json_decode($item['diaspora_meta'],true); + if($z) { + if(is_array($z) && array_key_exists('iv',$z)) + $x['diaspora_signature'] = crypto_unencapsulate($z,$key); + else + $x['diaspora_signature'] = $z; + if(! is_array($z)) + logger('encode_item: diaspora meta is not an array: ' . print_r($z,true)); + } + } logger('encode_item: ' . print_r($x,true), LOGGER_DATA); return $x; @@ -1407,7 +1405,7 @@ function encode_item_xchan($xchan) { return $ret; } -function encode_item_terms($terms) { +function encode_item_terms($terms,$mirror = false) { $ret = array(); $allowed_export_terms = array( TERM_UNKNOWN, TERM_HASHTAG, TERM_MENTION, TERM_CATEGORY, TERM_BOOKMARK ); @@ -1545,17 +1543,17 @@ function encode_item_flags($item) { $ret = array(); - if($item['item_restrict'] & ITEM_DELETED) + if(intval($item['item_deleted'])) $ret[] = 'deleted'; - if($item['item_restrict'] & ITEM_HIDDEN) + if(intval($item['item_hidden'])) $ret[] = 'hidden'; - if($item['item_flags'] & ITEM_THREAD_TOP) + if(intval($item['item_thread_top'])) $ret[] = 'thread_parent'; - if($item['item_flags'] & ITEM_NSFW) + if(intval($item['item_nsfw'])) $ret[] = 'nsfw'; - if($item['item_flags'] & ITEM_CONSENSUS) + if(intval($item['item_consensus'])) $ret[] = 'consensus'; - if($item['item_private']) + if(intval($item['item_private'])) $ret[] = 'private'; return $ret; @@ -1566,12 +1564,11 @@ function encode_mail($item) { $x['type'] = 'mail'; $x['encoding'] = 'zot'; - if(array_key_exists('mail_flags',$item) && ($item['mail_flags'] & MAIL_OBSCURED)) { - $key = get_config('system','prvkey'); + if(array_key_exists('mail_obscured',$item) && intval($item['mail_obscured'])) { if($item['title']) - $item['title'] = crypto_unencapsulate(json_decode_plus($item['title']),$key); + $item['title'] = base64url_decode(str_rot47($item['title'])); if($item['body']) - $item['body'] = crypto_unencapsulate(json_decode_plus($item['body']),$key); + $item['body'] = base64url_decode(str_rot47($item['body'])); } $x['message_id'] = $item['mid']; @@ -1589,7 +1586,7 @@ function encode_mail($item) { $x['flags'] = array(); - if($item['mail_flags'] & MAIL_RECALLED) { + if(intval($item['mail_recalled'])) { $x['flags'][] = 'recalled'; $x['title'] = ''; $x['body'] = ''; @@ -1617,19 +1614,19 @@ function get_mail_elements($x) { if($x['flags'] && is_array($x['flags'])) { if(in_array('recalled',$x['flags'])) { - $arr['mail_flags'] |= MAIL_RECALLED; + $arr['mail_recalled'] = 1; } } $key = get_config('system','pubkey'); - $arr['mail_flags'] |= MAIL_OBSCURED; - $arr['body'] = htmlspecialchars($arr['body'],ENT_COMPAT,'UTF-8',false); - if($arr['body']) - $arr['body'] = json_encode(crypto_encapsulate($arr['body'],$key)); - $arr['title'] = htmlspecialchars($arr['title'],ENT_COMPAT,'UTF-8',false); - if($arr['title']) - $arr['title'] = json_encode(crypto_encapsulate($arr['title'],$key)); + $arr['mail_obscured'] = 1; + if($arr['body']) { + $arr['body'] = str_rot47(base64url_encode($arr['body'])); + } + if($arr['title']) { + $arr['title'] = str_rot47(base64url_encode($arr['title'])); + } if($arr['created'] > datetime_convert()) $arr['created'] = datetime_convert(); @@ -1711,7 +1708,7 @@ function get_atom_elements($feed, $item, &$author) { $res['title'] = unxmlify($item->get_title()); $res['body'] = unxmlify($item->get_content()); $res['plink'] = unxmlify($item->get_link(0)); - $res['item_flags'] = ITEM_RSS; + $res['item_rss'] = 1; // removing the content of the title if its identically to the body @@ -2151,11 +2148,11 @@ function item_store($arr, $allow_exec = false) { // If a page layout is provided, ensure it exists and belongs to us. if(array_key_exists('layout_mid',$arr) && $arr['layout_mid']) { - $l = q("select item_restrict from item where mid = '%s' and uid = %d limit 1", + $l = q("select item_type from item where mid = '%s' and uid = %d limit 1", dbesc($arr['layout_mid']), intval($arr['uid']) ); - if((! $l) || (! ($l[0]['item_restrict'] & ITEM_PDL))) + if((! $l) || (! ($l[0]['item_type'] != ITEM_TYPE_PDL))) unset($arr['layout_mid']); } @@ -2184,12 +2181,13 @@ function item_store($arr, $allow_exec = false) { $arr['deny_cid'] = ((x($arr,'deny_cid')) ? trim($arr['deny_cid']) : ''); $arr['deny_gid'] = ((x($arr,'deny_gid')) ? trim($arr['deny_gid']) : ''); $arr['item_private'] = ((x($arr,'item_private')) ? intval($arr['item_private']) : 0 ); - $arr['item_flags'] = ((x($arr,'item_flags')) ? intval($arr['item_flags']) : 0 ); + $arr['item_wall'] = ((x($arr,'item_wall')) ? intval($arr['item_wall']) : 0 ); + $arr['item_type'] = ((x($arr,'item_type')) ? intval($arr['item_type']) : 0 ); // only detect language if we have text content, and if the post is private but not yet // obscured, make it so. - if(! ($arr['item_flags'] & ITEM_OBSCURED)) { + if((! array_key_exists('item_obscured',$arr)) || $arr['item_obscured'] == 0) { $arr['lang'] = detect_language($arr['body']); // apply the input filter here - if it is obscured it has been filtered already @@ -2199,7 +2197,7 @@ function item_store($arr, $allow_exec = false) { $channel = get_app()->get_channel(); if($channel['channel_hash'] === $arr['author_xchan']) { $arr['sig'] = base64url_encode(rsa_sign($arr['body'],$channel['channel_prvkey'])); - $arr['item_flags'] |= ITEM_VERIFIED; + $arr['item_verified'] = 1; } } @@ -2215,14 +2213,6 @@ function item_store($arr, $allow_exec = false) { } $arr = $translate['item']; } - if($arr['item_private']) { - $key = get_config('system','pubkey'); - $arr['item_flags'] = $arr['item_flags'] | ITEM_OBSCURED; - if($arr['title']) - $arr['title'] = json_encode(crypto_encapsulate($arr['title'],$key)); - if($arr['body']) - $arr['body'] = json_encode(crypto_encapsulate($arr['body'],$key)); - } } if((x($arr,'object')) && is_array($arr['object'])) { @@ -2264,16 +2254,16 @@ function item_store($arr, $allow_exec = false) { $arr['plink'] = ((x($arr,'plink')) ? notags(trim($arr['plink'])) : ''); $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['public_policy'] = ((x($arr,'public_policy')) ? notags(trim($arr['public_policy'])) : '' ); $arr['comment_policy'] = ((x($arr,'comment_policy')) ? notags(trim($arr['comment_policy'])) : 'contacts' ); + + if(! array_key_exists('item_unseen',$arr)) + $arr['item_unseen'] = 1; - $arr['item_unseen'] = ((array_key_exists('item_unseen',$arr)) ? intval($arr['item_unseen']) : 1); - - if($arr['comment_policy'] == 'none') - $arr['item_flags'] = $arr['item_flags'] | ITEM_NOCOMMENT; + if((! array_key_exists('item_nocomment',$arr)) && ($arr['comment_policy'] == 'none')) + $arr['item_nocomment'] = 1; // handle time travelers // Allow a bit of fudge in case somebody just has a slightly slow/fast clock @@ -2281,7 +2271,7 @@ function item_store($arr, $allow_exec = false) { $d1 = new DateTime('now +10 minutes', new DateTimeZone('UTC')); $d2 = new DateTime($arr['created'] . '+00:00'); if($d2 > $d1) - $arr['item_restrict'] = $arr['item_restrict'] | ITEM_DELAYED_PUBLISH; + $arr['item_delayed'] = 1; $arr['llink'] = z_root() . '/display/' . $arr['mid']; @@ -2297,7 +2287,7 @@ function item_store($arr, $allow_exec = false) { $deny_gid = $arr['deny_gid']; $public_policy = $arr['public_policy']; $comments_closed = $arr['comments_closed']; - $arr['item_flags'] = $arr['item_flags'] | ITEM_THREAD_TOP; + $arr['item_thread_top'] = 1; } else { @@ -2347,7 +2337,7 @@ function item_store($arr, $allow_exec = false) { } $parent_id = $r[0]['id']; - $parent_deleted = $r[0]['item_restrict'] & ITEM_DELETED; + $parent_deleted = $r[0]['item_deleted']; $allow_cid = $r[0]['allow_cid']; $allow_gid = $r[0]['allow_gid']; $deny_cid = $r[0]['deny_cid']; @@ -2355,8 +2345,8 @@ function item_store($arr, $allow_exec = false) { $public_policy = $r[0]['public_policy']; $comments_closed = $r[0]['comments_closed']; - if($r[0]['item_flags'] & ITEM_WALL) - $arr['item_flags'] = $arr['item_flags'] | ITEM_WALL; + if(intval($r[0]['item_wall'])) + $arr['item_wall'] = 1; // An uplinked comment might arrive with a downstream owner. // Fix it. @@ -2375,7 +2365,7 @@ function item_store($arr, $allow_exec = false) { // The original author commented, but as this is a comment, the permissions // weren't fixed up so it will still show the comment as private unless we fix it here. - if((intval($r[0]['item_flags']) & ITEM_UPLINK) && (! $r[0]['item_private'])) + if(intval($r[0]['item_uplink']) && (! $r[0]['item_private'])) $arr['item_private'] = 0; } else { @@ -2386,7 +2376,7 @@ function item_store($arr, $allow_exec = false) { } if($parent_deleted) - $arr['item_restrict'] = $arr['item_restrict'] | ITEM_DELETED; + $arr['item_deleted'] = 1; $r = q("SELECT `id` FROM `item` WHERE `mid` = '%s' AND `uid` = %d LIMIT 1", dbesc($arr['mid']), @@ -2498,10 +2488,9 @@ function item_store($arr, $allow_exec = false) { // update the commented timestamp on the parent - $z = q("select max(created) as commented from item where parent_mid = '%s' and uid = %d and not ( item_restrict & %d )>0 ", + $z = q("select max(created) as commented from item where parent_mid = '%s' and uid = %d and item_delayed = 0 ", dbesc($arr['parent_mid']), - intval($arr['uid']), - intval(ITEM_DELAYED_PUBLISH) + intval($arr['uid']) ); q("UPDATE item set commented = '%s', changed = '%s' WHERE id = %d", @@ -2516,7 +2505,7 @@ function item_store($arr, $allow_exec = false) { // so that we have an item in the DB that's marked deleted and won't store a fresh post // that isn't aware that we were already told to delete it. - if(! ($arr['item_restrict'] & ITEM_DELETED)) { + if(! intval($arr['item_deleted'])) { send_status_notifications($current_post,$arr); tag_deliver($arr['uid'],$current_post); } @@ -2563,17 +2552,8 @@ function item_store_update($arr,$allow_exec = false) { // override the unseen flag with the original - if(intval($arr['item_flags'])) - $arr['item_unseen'] = 0; + $arr['item_unseen'] = $orig[0]['item_unseen']; - if($orig[0]['item_flags'] & ITEM_VERIFIED) - $orig[0]['item_flags'] = $orig[0]['item_flags'] ^ ITEM_VERIFIED; - - if($orig[0]['item_flags'] & ITEM_OBSCURED) - $orig[0]['item_flags'] = $orig[0]['item_flags'] ^ ITEM_OBSCURED; - - $arr['item_flags'] = intval($arr['item_flags']) | $orig[0]['item_flags']; - $arr['item_restrict'] = intval($arr['item_restrict']) | $orig[0]['item_restrict']; if(array_key_exists('edit',$arr)) unset($arr['edit']); @@ -2586,19 +2566,20 @@ function item_store_update($arr,$allow_exec = false) { return $ret; } - if(! ($arr['item_flags'] & ITEM_OBSCURED)) { + if((! array_key_exists('item_obscured', $arr)) || $arr['item_obscured'] == 0) { $arr['lang'] = detect_language($arr['body']); - // apply the input filter here - if it is obscured it has been filtered already - $arr['body'] = trim(z_input_filter($arr['uid'],$arr['body'],$arr['mimetype'])); - if(local_channel() && (! $arr['sig'])) { - $channel = get_app()->get_channel(); - if($channel['channel_hash'] === $arr['author_xchan']) { - $arr['sig'] = base64url_encode(rsa_sign($arr['body'],$channel['channel_prvkey'])); - $arr['item_flags'] |= ITEM_VERIFIED; - } - } + // apply the input filter here - if it is obscured it has been filtered already + $arr['body'] = trim(z_input_filter($arr['uid'],$arr['body'],$arr['mimetype'])); + + if(local_channel() && (! $arr['sig'])) { + $channel = get_app()->get_channel(); + if($channel['channel_hash'] === $arr['author_xchan']) { + $arr['sig'] = base64url_encode(rsa_sign($arr['body'],$channel['channel_prvkey'])); + $arr['item_verified'] = 1; + } + } $allowed_languages = get_pconfig($arr['uid'],'system','allowed_languages'); @@ -2612,14 +2593,6 @@ function item_store_update($arr,$allow_exec = false) { } $arr = $translate['item']; } - if($arr['item_private']) { - $key = get_config('system','pubkey'); - $arr['item_flags'] = $arr['item_flags'] | ITEM_OBSCURED; - if($arr['title']) - $arr['title'] = json_encode(crypto_encapsulate($arr['title'],$key)); - if($arr['body']) - $arr['body'] = json_encode(crypto_encapsulate($arr['body'],$key)); - } } if((x($arr,'object')) && is_array($arr['object'])) { @@ -2677,13 +2650,38 @@ function item_store_update($arr,$allow_exec = false) { $arr['deny_gid'] = ((array_key_exists('deny_gid',$arr)) ? trim($arr['deny_gid']) : $orig[0]['deny_gid']); $arr['item_private'] = ((array_key_exists('item_private',$arr)) ? intval($arr['item_private']) : $orig[0]['item_private']); - $arr['title'] = ((array_key_exists('title',$arr)) ? trim($arr['title']) : $orig[0]['title']); - $arr['body'] = ((array_key_exists('body',$arr)) ? trim($arr['body']) : $orig[0]['body']); + $arr['title'] = ((array_key_exists('title',$arr) && strlen($arr['title'])) ? trim($arr['title']) : ''); + $arr['body'] = ((array_key_exists('body',$arr) && strlen($arr['body'])) ? trim($arr['body']) : ''); + $arr['html'] = ((array_key_exists('html',$arr) && strlen($arr['html'])) ? trim($arr['html']) : ''); + + $arr['attach'] = ((array_key_exists('attach',$arr)) ? notags(trim($arr['attach'])) : $orig[0]['attach']); + $arr['app'] = ((array_key_exists('app',$arr)) ? notags(trim($arr['app'])) : $orig[0]['app']); + + $arr['item_origin'] = ((array_key_exists('item_origin',$arr)) ? intval($arr['item_origin']) : $orig[0]['item_origin'] ); + $arr['item_unseen'] = ((array_key_exists('item_unseen',$arr)) ? intval($arr['item_unseen']) : $orig[0]['item_unseen'] ); + $arr['item_starred'] = ((array_key_exists('item_starred',$arr)) ? intval($arr['item_starred']) : $orig[0]['item_starred'] ); + $arr['item_uplink'] = ((array_key_exists('item_uplink',$arr)) ? intval($arr['item_uplink']) : $orig[0]['item_uplink'] ); + $arr['item_consensus'] = ((array_key_exists('item_consensus',$arr)) ? intval($arr['item_consensus']) : $orig[0]['item_consensus'] ); + $arr['item_wall'] = ((array_key_exists('item_wall',$arr)) ? intval($arr['item_wall']) : $orig[0]['item_wall'] ); + $arr['item_thread_top'] = ((array_key_exists('item_thread_top',$arr)) ? intval($arr['item_thread_top']) : $orig[0]['item_thread_top'] ); + $arr['item_notshown'] = ((array_key_exists('item_notshown',$arr)) ? intval($arr['item_notshown']) : $orig[0]['item_notshown'] ); + $arr['item_nsfw'] = ((array_key_exists('item_nsfw',$arr)) ? intval($arr['item_nsfw']) : $orig[0]['item_nsfw'] ); + $arr['item_relay'] = ((array_key_exists('item_relay',$arr)) ? intval($arr['item_relay']) : $orig[0]['item_relay'] ); + $arr['item_mentionsme'] = ((array_key_exists('item_mentionsme',$arr)) ? intval($arr['item_mentionsme']) : $orig[0]['item_mentionsme'] ); + $arr['item_nocomment'] = ((array_key_exists('item_nocomment',$arr)) ? intval($arr['item_nocomment']) : $orig[0]['item_nocomment'] ); + $arr['item_obscured'] = ((array_key_exists('item_obscured',$arr)) ? intval($arr['item_obscured']) : $orig[0]['item_obscured'] ); + $arr['item_verified'] = ((array_key_exists('item_verified',$arr)) ? intval($arr['item_verified']) : $orig[0]['item_verified'] ); + $arr['item_retained'] = ((array_key_exists('item_retained',$arr)) ? intval($arr['item_retained']) : $orig[0]['item_retained'] ); + $arr['item_rss'] = ((array_key_exists('item_rss',$arr)) ? intval($arr['item_rss']) : $orig[0]['item_rss'] ); + $arr['item_deleted'] = ((array_key_exists('item_deleted',$arr)) ? intval($arr['item_deleted']) : $orig[0]['item_deleted'] ); + $arr['item_type'] = ((array_key_exists('item_type',$arr)) ? intval($arr['item_type']) : $orig[0]['item_type'] ); + $arr['item_hidden'] = ((array_key_exists('item_hidden',$arr)) ? intval($arr['item_hidden']) : $orig[0]['item_hidden'] ); + $arr['item_unpublished'] = ((array_key_exists('item_unpublished',$arr)) ? intval($arr['item_unpublished']) : $orig[0]['item_unpublished'] ); + $arr['item_delayed'] = ((array_key_exists('item_delayed',$arr)) ? intval($arr['item_delayed']) : $orig[0]['item_delayed'] ); + $arr['item_pending_remove'] = ((array_key_exists('item_pending_remove',$arr)) ? intval($arr['item_pending_remove']) : $orig[0]['item_pending_remove'] ); + $arr['item_blocked'] = ((array_key_exists('item_blocked',$arr)) ? intval($arr['item_blocked']) : $orig[0]['item_blocked'] ); + - $arr['attach'] = ((x($arr,'attach')) ? notags(trim($arr['attach'])) : $orig[0]['attach']); - $arr['app'] = ((x($arr,'app')) ? notags(trim($arr['app'])) : $orig[0]['app']); -// $arr['item_restrict'] = ((x($arr,'item_restrict')) ? intval($arr['item_restrict']) : $orig[0]['item_restrict'] ); -// $arr['item_flags'] = ((x($arr,'item_flags')) ? intval($arr['item_flags']) : $orig[0]['item_flags'] ); $arr['sig'] = ((x($arr,'sig')) ? $arr['sig'] : ''); $arr['layout_mid'] = ((array_key_exists('layout_mid',$arr)) ? dbesc($arr['layout_mid']) : $orig[0]['layout_mid'] ); @@ -2794,11 +2792,10 @@ function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id, $x = array('signer' => $diaspora_handle, 'body' => $signed_body, 'signed_text' => $signed_text, 'signature' => base64_encode($authorsig)); - $key = get_config('system','pubkey'); - $y = crypto_encapsulate(json_encode($x),$key); + $y = json_encode($x); $r = q("update item set diaspora_meta = '%s' where id = %d", - dbesc(json_encode($y)), + dbesc($y), intval($post_id) ); @@ -2923,8 +2920,8 @@ function tag_deliver($uid, $item_id) { $item = $i[0]; - if(($item['source_xchan']) && ($item['item_flags'] & ITEM_UPLINK) - && ($item['item_flags'] & ITEM_THREAD_TOP) && ($item['edited'] != $item['created'])) { + if(($item['source_xchan']) && intval($item['item_uplink']) + && intval($item['item_thread_top']) && ($item['edited'] != $item['created'])) { // this is an update (edit) to a post which was already processed by us and has a second delivery chain // Just start the second delivery chain to deliver the updated post proc_run('php','include/notifier.php','tgroup',$item['id']); @@ -2946,7 +2943,7 @@ function tag_deliver($uid, $item_id) { if($obj['id'] !== $u[0]['channel_hash']) $poke_notify = false; } - if($item['item_restrict'] & ITEM_DELETED) + if(intval($item['item_deleted'])) $poke_notify = false; $verb = urldecode(substr($item['verb'],strpos($item['verb'],'#')+1)); @@ -3023,13 +3020,13 @@ function tag_deliver($uid, $item_id) { // This might be a followup (e.g. comment) by the original post author to a tagged forum // If so setup a second delivery chain - if( ! ($item['item_flags'] & ITEM_THREAD_TOP)) { + if( ! intval($item['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)) { + if(($x) && intval($x[0]['item_uplink'])) { start_delivery_chain($u[0],$item,$item_id,$x[0]); } } @@ -3057,9 +3054,8 @@ function tag_deliver($uid, $item_id) { if($mention) { logger('tag_deliver: mention found for ' . $u[0]['channel_name']); - - $r = q("update item set item_flags = ( item_flags | %d ) where id = %d", - intval(ITEM_MENTIONSME), + + $r = q("update item set item_mentionsme = 1 where id = %d", intval($item_id) ); @@ -3069,7 +3065,7 @@ function tag_deliver($uid, $item_id) { $body = ''; - if($item['item_flags'] & ITEM_OBSCURED) { + if(intval($item['item_obscured'])) { $key = get_config('system','prvkey'); if($item['body']) $body = crypto_unencapsulate(json_decode_plus($item['body']),$key); @@ -3153,10 +3149,8 @@ function tag_deliver($uid, $item_id) { // prevent delivery looping - only proceed // if the message originated elsewhere and is a top-level post - if(($item['item_flags'] & ITEM_WALL) - || ($item['item_flags'] & ITEM_ORIGIN) - || (!($item['item_flags'] & ITEM_THREAD_TOP)) - || ($item['id'] != $item['parent'])) { + + if(intval($item['item_wall']) || intval($item['item_origin']) || (! intval($item['item_thread_top'])) || ($item['id'] != $item['parent'])) { logger('tag_deliver: item was local or a comment. rejected.'); return; } @@ -3181,10 +3175,9 @@ function tgroup_check($uid,$item) { // or is a followup and we have already accepted the top level post as an uplink if($item['mid'] != $item['parent_mid']) { - $r = q("select id from item where mid = '%s' and uid = %d and ( item_flags & %d )>0 limit 1", + $r = q("select id from item where mid = '%s' and uid = %d and item_uplink = 1 limit 1", dbesc($item['parent_mid']), - intval($uid), - intval(ITEM_UPLINK) + intval($uid) ); if($r) return true; @@ -3230,7 +3223,7 @@ function tgroup_check($uid,$item) { $body = $item['body']; - if(array_key_exists('item_flags',$item) && ($item['item_flags'] & ITEM_OBSCURED) && $body) { + if(array_key_exists('item_obscured',$item) && intval($item['item_obscured']) && $body) { $key = get_config('system','prvkey'); $body = crypto_unencapsulate(json_decode($body,true),$key); } @@ -3293,20 +3286,14 @@ function start_delivery_chain($channel, $item, $item_id, $parent) { if((! $private) && $new_public_policy) $private = 1; - $flag_bits = $item['item_flags'] | ITEM_WALL; - - // The message didn't necessarily originate on this site, (we'll honour it if it did), - // but the parent post of this thread will be reset as a local post, as it is the top of - // this delivery chain and is coming from this site, regardless of where the original - // originated. - - if(! $parent) - $flag_bits = $flag_bits | ITEM_ORIGIN; - // unset the nocomment bit if it's there. + $item_wall = 1; + $item_origin = 1; + $item_uplink = 0; + $item_nocomment = 0; + $item_obscured = 0; - if($flag_bits & ITEM_NOCOMMENT) - $flag_bits = $flag_bits ^ ITEM_NOCOMMENT; + $flag_bits = $item['item_flags']; // maintain the original source, which will be the original item owner and was stored in source_xchan // when we created the delivery fork @@ -3318,7 +3305,7 @@ function start_delivery_chain($channel, $item, $item_id, $parent) { ); } else { - $flag_bits = $flag_bits | ITEM_UPLINK; + $item_uplink = 1; $r = q("update item set source_xchan = owner_xchan where id = %d", intval($item_id) ); @@ -3327,29 +3314,11 @@ function start_delivery_chain($channel, $item, $item_id, $parent) { $title = $item['title']; $body = $item['body']; - if($private) { - if(!($flag_bits & ITEM_OBSCURED)) { - $key = get_config('system','pubkey'); - $flag_bits = $flag_bits|ITEM_OBSCURED; - if($title) - $title = json_encode(crypto_encapsulate($title,$key)); - if($body) - $body = json_encode(crypto_encapsulate($body,$key)); - } - } - else { - if($flag_bits & ITEM_OBSCURED) { - $key = get_config('system','prvkey'); - $flag_bits = $flag_bits ^ ITEM_OBSCURED; - if($title) - $title = crypto_unencapsulate(json_decode($title,true),$key); - if($body) - $body = crypto_unencapsulate(json_decode($body,true),$key); - } - } - - $r = q("update item set item_flags = %d, owner_xchan = '%s', allow_cid = '%s', allow_gid = '%s', - deny_cid = '%s', deny_gid = '%s', item_private = %d, public_policy = '%s', comment_policy = '%s', title = '%s', body = '%s' where id = %d", + $r = q("update item set item_uplink = %d, item_nocomment = %d, item_obscured = %d, item_flags = %d, owner_xchan = '%s', allow_cid = '%s', allow_gid = '%s', + deny_cid = '%s', deny_gid = '%s', item_private = %d, public_policy = '%s', comment_policy = '%s', title = '%s', body = '%s', item_wall = %d, item_origin = %d where id = %d", + intval($item_uplink), + intval($item_nocomment), + intval($item_obscured), intval($flag_bits), dbesc($channel['channel_hash']), dbesc($channel['channel_allow_cid']), @@ -3361,6 +3330,8 @@ function start_delivery_chain($channel, $item, $item_id, $parent) { dbesc(map_scope($channel['channel_w_comment'])), dbesc($title), dbesc($body), + intval($item_wall), + intval($item_origin), intval($item_id) ); @@ -3389,7 +3360,7 @@ function check_item_source($uid, $item) { if(! $r) return false; - $x = q("select abook_their_perms, abook_flags from abook where abook_channel = %d and abook_xchan = '%s' limit 1", + $x = q("select abook_their_perms, abook_feed from abook where abook_channel = %d and abook_xchan = '%s' limit 1", intval($uid), dbesc($item['owner_xchan']) ); @@ -3400,7 +3371,7 @@ function check_item_source($uid, $item) { if(! ($x[0]['abook_their_perms'] & PERMS_A_REPUBLISH)) return false; - if($item['item_private'] && (! ($x[0]['abook_flags'] & ABOOK_FLAG_FEED))) + if($item['item_private'] && (! intval($x[0]['abook_feed']))) return false; if($r[0]['src_channel_xchan'] === $item['owner_xchan']) @@ -3471,6 +3442,8 @@ function post_is_importable($item,$abook) { if($exclude) { foreach($exclude as $word) { $word = trim($word); + if(! $word) + continue; if(substr($word,0,1) === '#' && $tags) { foreach($tags as $t) if(($t['type'] == TERM_HASHTAG) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*'))) @@ -3490,6 +3463,8 @@ function post_is_importable($item,$abook) { if($include) { foreach($include as $word) { $word = trim($word); + if(! $word) + continue; if(substr($word,0,1) === '#' && $tags) { foreach($tags as $t) if(($t['type'] == TERM_HASHTAG) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*'))) @@ -3518,8 +3493,10 @@ function mail_store($arr) { return 0; } - if((strpos($arr['body'],'<') !== false) || (strpos($arr['body'],'>') !== false)) - $arr['body'] = escape_tags($arr['body']); + if(! $arr['mail_obscured']) { + if((strpos($arr['body'],'<') !== false) || (strpos($arr['body'],'>') !== false)) + $arr['body'] = escape_tags($arr['body']); + } if(array_key_exists('attach',$arr) && is_array($arr['attach'])) $arr['attach'] = json_encode($arr['attach']); @@ -3530,7 +3507,7 @@ function mail_store($arr) { $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']) : NULL_DATE); - $arr['title'] = ((x($arr,'title')) ? notags(trim($arr['title'])) : ''); + $arr['title'] = ((x($arr,'title')) ? trim($arr['title']) : ''); $arr['parent_mid'] = ((x($arr,'parent_mid')) ? notags(trim($arr['parent_mid'])) : ''); $arr['body'] = ((x($arr,'body')) ? trim($arr['body']) : ''); @@ -3545,11 +3522,17 @@ function mail_store($arr) { dbesc($arr['mid']), intval($arr['channel_id']) ); + if($r) { logger('mail_store: duplicate item ignored. ' . print_r($arr,true)); return 0; } + if(! $r && $arr['mail_recalled'] == 1) { + logger('mail_store: recalled item not found. ' . print_r($arr,true)); + return 0; + } + call_hooks('post_mail',$arr); if(x($arr,'cancel')) { @@ -3685,7 +3668,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { if($r) { $item = $r[0]; - if(! ($item['item_restrict'] & ITEM_DELETED)) { + if(! intval($item['item_deleted'])) { logger('consume_feed: deleting item ' . $item['id'] . ' mid=' . base64url_decode($item['mid']), LOGGER_DEBUG); drop_item($item['id'],false); } @@ -4183,22 +4166,23 @@ function item_expire($uid,$days) { $expire_network_only = 1; + $sql_extra = ((intval($expire_network_only)) ? " AND item_wall = 0 " : ""); + $expire_limit = get_config('system','expire_limit'); if(! intval($expire_limit)) $expire_limit = 5000; - $sql_extra = ((intval($expire_network_only)) ? " AND (item_flags & " . intval(ITEM_WALL) . ") = 0 " : ""); + $item_normal = item_normal(); $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `created` < %s - INTERVAL %s AND `id` = `parent` $sql_extra - AND ( item_flags & %d ) = 0 - AND ( item_restrict = 0 ) LIMIT $expire_limit ", + AND item_retained = 0 + $item_normal LIMIT $expire_limit ", intval($uid), - db_utcnow(), db_quoteinterval(intval($days).' DAY'), - intval(ITEM_RETAINED) + db_utcnow(), db_quoteinterval(intval($days).' DAY') ); if(! $r) @@ -4222,7 +4206,7 @@ function item_expire($uid,$days) { retain_item($item['id']); continue; } - if($item['item_flags'] & ITEM_STARRED) { + if(intval($item['item_starred'])) { retain_item($item['id']); continue; } @@ -4234,8 +4218,7 @@ function item_expire($uid,$days) { } function retain_item($id) { - $r = q("update item set item_flags = (item_flags | %d ) where id = %d", - intval(ITEM_RETAINED), + $r = q("update item set item_retained = 1 where id = %d", intval($id) ); } @@ -4280,7 +4263,7 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal intval($id) ); - if((! $r) || (($r[0]['item_restrict'] & ITEM_DELETED) && ($stage === DROPITEM_NORMAL))) { + if((! $r) || (intval($r[0]['item_deleted']) && ($stage === DROPITEM_NORMAL))) { if(! $interactive) return 0; notice( t('Item not found.') . EOL); @@ -4316,10 +4299,16 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal // set the deleted flag immediately on this item just in case the // hook calls a remote process which loops. We'll delete it properly in a second. - $r = q("UPDATE item SET item_restrict = ( item_restrict | %d ) WHERE id = %d", - intval(($linked_item && ! $force) ? ITEM_HIDDEN : ITEM_DELETED), - intval($item['id']) - ); + if(($linked_item) && (! $force)) { + $r = q("UPDATE item SET item_hidden = 1 WHERE id = %d", + intval($item['id']) + ); + } + else { + $r = q("UPDATE item SET item_deleted = 1 WHERE id = %d", + intval($item['id']) + ); + } $arr = array('item' => $item, 'interactive' => $interactive, 'stage' => $stage); call_hooks('drop_item', $arr ); @@ -4348,7 +4337,7 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal // We'll rely on the undocumented behaviour that DROPITEM_PHASE1 is (hopefully) only // set if we know we're going to send delete notifications out to others. - if((($item['item_flags'] & ITEM_WALL) && ($stage != DROPITEM_PHASE2)) || ($stage == DROPITEM_PHASE1)) + if((intval($item['item_wall']) && ($stage != DROPITEM_PHASE2)) || ($stage == DROPITEM_PHASE1)) proc_run('php','include/notifier.php','drop',$notify_id); goaway($a->get_baseurl() . '/' . $_SESSION['return_url']); @@ -4380,9 +4369,8 @@ function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL, $force = false) { switch($stage) { case DROPITEM_PHASE2: - $r = q("UPDATE item SET item_restrict = ( item_restrict | %d ), body = '', title = '', + $r = q("UPDATE item SET item_pending_remove = 1, body = '', title = '', changed = '%s', edited = '%s' WHERE id = %d", - intval(ITEM_PENDING_REMOVE), dbesc(datetime_convert()), dbesc(datetime_convert()), intval($item['id']) @@ -4390,30 +4378,37 @@ function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL, $force = false) { break; case DROPITEM_PHASE1: - $r = q("UPDATE item SET item_restrict = ( item_restrict | %d ), - changed = '%s', edited = '%s' WHERE id = %d", - intval(($linked_item && ! $force) ? ITEM_HIDDEN : ITEM_DELETED), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - intval($item['id']) - ); + if($linked_item && ! $force) { + $r = q("UPDATE item SET item_hidden = 1, + changed = '%s', edited = '%s' WHERE id = %d", + dbesc(datetime_convert()), + dbesc(datetime_convert()), + intval($item['id']) + ); + } + else { + $r = q("UPDATE item set item_deleted = 1, changed = '%s', edited = '%s' where id = %d", + dbesc(datetime_convert()), + dbesc(datetime_convert()), + intval($item['id']) + ); + } + break; case DROPITEM_NORMAL: default: if($linked_item && ! $force) { - $r = q("UPDATE item SET item_restrict = ( item_restrict | %d ), + $r = q("UPDATE item SET item_hidden = 1, changed = '%s', edited = '%s' WHERE id = %d", - intval(ITEM_HIDDEN), dbesc(datetime_convert()), dbesc(datetime_convert()), intval($item['id']) ); } else { - $r = q("UPDATE item SET item_restrict = ( item_restrict | %d ), body = '', title = '', + $r = q("UPDATE item SET item_deleted = 1, body = '', title = '', changed = '%s', edited = '%s' WHERE id = %d", - intval(ITEM_DELETED), dbesc(datetime_convert()), dbesc(datetime_convert()), intval($item['id']) @@ -4429,6 +4424,18 @@ function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL, $force = false) { intval($item['uid']) ); + // remove delivery reports + + $c = q("select channel_hash from channel where channel_id = %d limit 1", + intval($item['uid']) + ); + if($c) { + q("delete from dreport where dreport_xchan = '%s' and dreport_mid = '%s'", + dbesc($c[0]['channel_hash']), + dbesc($item['mid']) + ); + } + // network deletion request. Keep the message structure so that we can deliver delete notifications. // Come back after several days (or perhaps a month) to do the lowlevel delete (DROPITEM_PHASE2). @@ -4458,12 +4465,12 @@ function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL, $force = false) { function first_post_date($uid,$wall = false) { - $wall_sql = (($wall) ? sprintf(" and (item_flags & %d)>0 ", ITEM_WALL) : "" ); + $wall_sql = (($wall) ? " and item_wall = 1 " : "" ); + $item_normal = item_normal(); $r = q("select id, created from item - where item_restrict = %d and uid = %d and id = parent $wall_sql + where uid = %d and id = parent $item_normal $wall_sql order by created asc limit 1", - intval(ITEM_VISIBLE), intval($uid) ); @@ -4664,23 +4671,23 @@ function zot_feed($uid,$observer_hash,$arr) { $groupby = 'GROUP BY parent'; } + $item_normal = item_normal(); + if(is_sys_channel($uid)) { $r = q("SELECT parent, created, postopts from item WHERE uid != %d - AND item_private = 0 AND item_restrict = 0 AND uid in (" . stream_perms_api_uids(PERMS_PUBLIC,10,1) . ") - AND (item_flags & %d) > 0 - $sql_extra $groupby ORDER BY created ASC $limit", - intval($uid), - intval(ITEM_WALL) + $item_normal + AND item_wall = 1 + and item_private = 0 $sql_extra $groupby ORDER BY created ASC $limit", + intval($uid) ); } else { $r = q("SELECT parent, created, postopts from item - WHERE uid = %d AND item_restrict = 0 - AND (item_flags & %d) > 0 + WHERE uid = %d $item_normal + AND item_wall = 1 $sql_extra $groupby ORDER BY created ASC $limit", - intval($uid), - intval(ITEM_WALL) + intval($uid) ); } @@ -4693,10 +4700,10 @@ function zot_feed($uid,$observer_hash,$arr) { $parents_str = ids_to_querystr($r,'parent'); $sys_query = ((is_sys_channel($uid)) ? $sql_extra : ''); + $item_normal = item_normal(); $items = q("SELECT `item`.*, `item`.`id` AS `item_id` FROM `item` - WHERE `item`.`item_restrict` = 0 - AND `item`.`parent` IN ( %s ) $sys_query ", + WHERE `item`.`parent` IN ( %s ) $item_normal $sys_query ", dbesc($parents_str) ); } @@ -4734,6 +4741,8 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C $def_acl = ''; $item_uids = ' true '; + $item_normal = item_normal(); + if ($arr['uid']) $uid= $arr['uid']; @@ -4744,13 +4753,19 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C } if($arr['star']) - $sql_options .= " and (item_flags & " . intval(ITEM_STARRED) . ")>0 "; + $sql_options .= " and item_starred = 1 "; if($arr['wall']) - $sql_options .= " and (item_flags & " . intval(ITEM_WALL) . ")>0 "; + $sql_options .= " and item_wall = 1 "; - $sql_extra = " AND item.parent IN ( SELECT parent FROM item WHERE (item_flags & " . intval(ITEM_THREAD_TOP) . ")>0 $sql_options ) "; + if($arr['item_id']) + $sql_options .= " and parent = " . intval($arr['item_id']) . " "; + if($arr['mid']) + $sql_options .= " and parent_mid = '" . dbesc($arr['mid']) . "' "; + + $sql_extra = " AND item.parent IN ( SELECT parent FROM item WHERE item_thread_top = 1 $sql_options ) "; + if($arr['since_id']) $sql_extra .= " and item.id > " . $since_id . " "; @@ -4780,19 +4795,19 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C return $result; } - $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND (( author_xchan IN ( $contact_str ) OR owner_xchan in ( $contact_str)) or allow_gid like '" . protect_sprintf('%<' . dbesc($r[0]['hash']) . '>%') . "' ) and id = parent and item_restrict = 0 ) "; + $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND (( author_xchan IN ( $contact_str ) OR owner_xchan in ( $contact_str)) or allow_gid like '" . protect_sprintf('%<' . dbesc($r[0]['hash']) . '>%') . "' ) and id = parent $item_normal ) "; $x = group_rec_byhash($uid,$r[0]['hash']); $result['headline'] = sprintf( t('Collection: %s'),$x['name']); } elseif($arr['cid'] && $uid) { - $r = q("SELECT abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_channel = %d and not ( abook_flags & " . intval(ABOOK_FLAG_BLOCKED) . ")>0 limit 1", + $r = q("SELECT abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_channel = %d and abook_blocked = 0 limit 1", intval($arr['cid']), intval(local_channel()) ); 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']) . "' ) $item_normal ) "; $result['headline'] = sprintf( t('Connection: %s'),$r[0]['xchan_name']); } else { $result['message'] = t('Connection not found.'); @@ -4813,24 +4828,24 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C } if($arr['search']) { - if(strpos($arr['search'],'#') === 0) - $sql_extra .= term_query('item',substr($arr['search'],1),TERM_HASHTAG); - else - $sql_extra .= sprintf(" AND item.body like '%s' ", - dbesc(protect_sprintf('%' . $arr['search'] . '%')) - ); - } - if (strlen($arr['file'])) { - $sql_extra .= term_query('item',$arr['files'],TERM_FILE); - } + if(strpos($arr['search'],'#') === 0) + $sql_extra .= term_query('item',substr($arr['search'],1),TERM_HASHTAG); + else + $sql_extra .= sprintf(" AND item.body like '%s' ", + dbesc(protect_sprintf('%' . $arr['search'] . '%')) + ); + } - if ($arr['conv'] && $channel) { - $sql_extra .= sprintf(" AND parent IN (SELECT distinct parent from item where ( author_xchan like '%s' or ( item_flags & %d )>0)) ", - dbesc(protect_sprintf($uidhash)), - intval(ITEM_MENTIONSME) - ); - } + if(strlen($arr['file'])) { + $sql_extra .= term_query('item',$arr['files'],TERM_FILE); + } + + if($arr['conv'] && $channel) { + $sql_extra .= sprintf(" AND parent IN (SELECT distinct parent from item where ( author_xchan like '%s' or item_mentionsme = 1 )) ", + dbesc(protect_sprintf($uidhash)) + ); + } if (($client_mode & CLIENT_MODE_UPDATE) && (! ($client_mode & CLIENT_MODE_LOAD))) { // only setup pagination on initial page view @@ -4865,19 +4880,23 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C } } - $simple_update = (($client_mode & CLIENT_MODE_UPDATE) ? " and ( item.item_unseen = 1 ) " : ''); - if ($client_mode & CLIENT_MODE_LOAD) - $simple_update = ''; + $simple_update = (($client_mode & CLIENT_MODE_UPDATE) ? " and item.item_unseen = 1 " : ''); + if($client_mode & CLIENT_MODE_LOAD) + $simple_update = ''; //$start = dba_timer(); require_once('include/security.php'); $sql_extra .= item_permissions_sql($channel['channel_id'],$observer_hash); - if ($arr['pages']) - $item_restrict = " AND (item_restrict & " . ITEM_WEBPAGE . ") "; + + if($arr['pages']) + $item_restrict = " AND item_type = " . ITEM_TYPE_WEBPAGE . " "; else - $item_restrict = " AND item_restrict = 0 "; + $item_restrict = " AND item_type = 0 "; + + if($arr['item_type'] === '*') + $item_restrict = ''; if ($arr['nouveau'] && ($client_mode & CLIENT_MODE_LOAD) && $channel) { // "New Item View" - show all items unthreaded in reverse created date order @@ -4911,10 +4930,9 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C left join abook on item.author_xchan = abook.abook_xchan WHERE $item_uids $item_restrict AND item.parent = item.id - and ((abook.abook_flags & %d) = 0 or abook.abook_flags is null) + and (abook.abook_blocked = 0 or abook.abook_flags is null) $sql_extra3 $sql_extra $sql_nets - ORDER BY item.$ordering DESC $pager_sql ", - intval(ABOOK_FLAG_BLOCKED) + ORDER BY item.$ordering DESC $pager_sql " ); } @@ -4923,9 +4941,8 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C $r = q("SELECT item.parent AS item_id FROM item left join abook on item.author_xchan = abook.abook_xchan WHERE $item_uids $item_restrict $simple_update - and ((abook.abook_flags & %d) = 0 or abook.abook_flags is null) - $sql_extra3 $sql_extra $sql_nets ", - intval(ABOOK_FLAG_BLOCKED) + and (abook.abook_blocked = 0 or abook.abook_flags is null) + $sql_extra3 $sql_extra $sql_nets " ); } @@ -4981,12 +4998,14 @@ function update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remo if(! $post_id) return; - if($webpage & ITEM_WEBPAGE) + if($webpage == ITEM_TYPE_WEBPAGE) $page_type = 'WEBPAGE'; - elseif($webpage & ITEM_BUILDBLOCK) + elseif($webpage == ITEM_TYPE_BLOCK) $page_type = 'BUILDBLOCK'; - elseif($webpage & ITEM_PDL) + elseif($webpage == ITEM_TYPE_PDL) $page_type = 'PDL'; + elseif($webpage == ITEM_TYPE_DOC) + $page_type = 'docfile'; elseif($namespace && $remote_id) { $page_type = $namespace; $pagetitle = $remote_id; diff --git a/include/js_strings.php b/include/js_strings.php index cae8da5de..a21461a52 100644 --- a/include/js_strings.php +++ b/include/js_strings.php @@ -39,7 +39,50 @@ function js_strings() { '$t14' => t('about a year'), '$t15' => t('%d years'), '$t16' => t(' '), // wordSeparator - '$t17' => ((t('timeago.numbers') != 'timeago.numbers') ? t('timeago.numbers') : '[]') + '$t17' => ((t('timeago.numbers') != 'timeago.numbers') ? t('timeago.numbers') : '[]'), + '$January' => t('January'), + '$February' => t('February'), + '$March' => t('March'), + '$April' => t('April'), + '$May' => t('May','long'), + '$June' => t('June'), + '$July' => t('July'), + '$August' => t('August'), + '$September' => t('September'), + '$October' => t('October'), + '$November' => t('November'), + '$December' => t('December'), + '$Jan' => t('Jan'), + '$Feb' => t('Feb'), + '$Mar' => t('Mar'), + '$Apr' => t('Apr'), + '$MayShort' => t('May','short'), + '$Jun' => t('Jun'), + '$Jul' => t('Jul'), + '$Aug' => t('Aug'), + '$Sep' => t('Sep'), + '$Oct' => t('Oct'), + '$Nov' => t('Nov'), + '$Dec' => t('Dec'), + '$Sunday' => t('Sunday'), + '$Monday' => t('Monday'), + '$Tuesday' => t('Tuesday'), + '$Wednesday' => t('Wednesday'), + '$Thursday' => t('Thursday'), + '$Friday' => t('Friday'), + '$Saturday' => t('Saturday'), + '$Sun' => t('Sun'), + '$Mon' => t('Mon'), + '$Tue' => t('Tue'), + '$Wed' => t('Wed'), + '$Thu' => t('Thu'), + '$Fri' => t('Fri'), + '$Sat' => t('Sat'), + '$today' => t('today','calendar'), + '$month' => t('month','calendar'), + '$week' => t('week','calendar'), + '$day' => t('day','calendar'), + '$allday' => t('All day','calendar') )); } diff --git a/include/language.php b/include/language.php index 7dbe3dd02..59979aa85 100644 --- a/include/language.php +++ b/include/language.php @@ -120,7 +120,11 @@ function load_translation_table($lang, $install = false) { global $a; $a->strings = array(); - if(file_exists("view/$lang/strings.php")) { + + if(file_exists("view/$lang/hstrings.php")) { + include("view/$lang/hstrings.php"); + } + elseif(file_exists("view/$lang/strings.php")) { include("view/$lang/strings.php"); } @@ -129,7 +133,10 @@ function load_translation_table($lang, $install = false) { if ($plugins !== false) { foreach($plugins as $p) { $name = $p['name']; - if(file_exists("addon/$name/lang/$lang/strings.php")) { + if(file_exists("addon/$name/lang/$lang/hstrings.php")) { + include("addon/$name/lang/$lang/hstrings.php"); + } + elseif(file_exists("addon/$name/lang/$lang/strings.php")) { include("addon/$name/lang/$lang/strings.php"); } } @@ -139,7 +146,10 @@ function load_translation_table($lang, $install = false) { // Allow individual strings to be over-ridden on this site // Either for the default language or for all languages - if(file_exists("view/local-$lang/strings.php")) { + if(file_exists("view/local-$lang/hstrings.php")) { + include("view/local-$lang/hstrings.php"); + } + elseif(file_exists("view/local-$lang/strings.php")) { include("view/local-$lang/strings.php"); } } diff --git a/include/menu.php b/include/menu.php index fc8aa1386..075372515 100644 --- a/include/menu.php +++ b/include/menu.php @@ -3,9 +3,10 @@ require_once('include/security.php'); require_once('include/bbcode.php'); + function menu_fetch($name,$uid,$observer_xchan) { - $sql_options = permissions_sql($uid); + $sql_options = permissions_sql($uid,$observer_xchan); $r = q("select * from menu where menu_channel_id = %d and menu_name = '%s' limit 1", intval($uid), @@ -237,7 +238,6 @@ function menu_edit($arr) { return false; } - $r = q("select * from menu where menu_id = %d and menu_channel_id = %d limit 1", intval($menu_id), intval($menu_channel_id) @@ -299,19 +299,18 @@ function menu_add_item($menu_id, $uid, $arr) { $channel = get_app()->get_channel(); } - $str_group_allow = perms2str($arr['group_allow']); - $str_contact_allow = perms2str($arr['contact_allow']); - $str_group_deny = perms2str($arr['group_deny']); - $str_contact_deny = perms2str($arr['contact_deny']); + $acl = new AccessList($channel); + $acl->set_from_array($arr); + $p = $acl->get(); $r = q("insert into menu_item ( mitem_link, mitem_desc, mitem_flags, allow_cid, allow_gid, deny_cid, deny_gid, mitem_channel_id, mitem_menu_id, mitem_order ) values ( '%s', '%s', %d, '%s', '%s', '%s', '%s', %d, %d, %d ) ", dbesc($mitem_link), dbesc($mitem_desc), intval($mitem_flags), - dbesc($str_contact_allow), - dbesc($str_group_allow), - dbesc($str_contact_deny), - dbesc($str_group_deny), + dbesc($p['allow_cid']), + dbesc($p['allow_gid']), + dbesc($p['deny_cid']), + dbesc($p['deny_gid']), intval($uid), intval($menu_id), intval($mitem_order) @@ -341,19 +340,19 @@ function menu_edit_item($menu_id, $uid, $arr) { $channel = get_app()->get_channel(); } - $str_group_allow = perms2str($arr['group_allow']); - $str_contact_allow = perms2str($arr['contact_allow']); - $str_group_deny = perms2str($arr['group_deny']); - $str_contact_deny = perms2str($arr['contact_deny']); + $acl = new AccessList($channel); + $acl->set_from_array($arr); + $p = $acl->get(); + $r = q("update menu_item set mitem_link = '%s', mitem_desc = '%s', mitem_flags = %d, allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', mitem_order = %d where mitem_channel_id = %d and mitem_menu_id = %d and mitem_id = %d", dbesc($mitem_link), dbesc($mitem_desc), intval($mitem_flags), - dbesc($str_contact_allow), - dbesc($str_group_allow), - dbesc($str_contact_deny), - dbesc($str_group_deny), + dbesc($p['allow_cid']), + dbesc($p['allow_gid']), + dbesc($p['deny_cid']), + dbesc($p['deny_gid']), intval($mitem_order), intval($uid), intval($menu_id), @@ -391,7 +390,7 @@ function menu_del_item($menu_id,$uid,$item_id) { function menu_sync_packet($uid,$observer_hash,$menu_id,$delete = false) { $r = menu_fetch_id($menu_id,$uid); if($r) { - $m = menu_fetch($r['menu_name'],$uid,$observer_hash); + $m = menu_fetch($r['menu_name'],$uid,$observer_hash); if($m) { if($delete) $m['menu_delete'] = 1; diff --git a/include/message.php b/include/message.php index bfc92cd6d..4b0236db8 100644 --- a/include/message.php +++ b/include/message.php @@ -49,6 +49,7 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto=' // look for any existing conversation structure + if(strlen($replyto)) { $r = q("select convid from mail where channel_id = %d and ( mid = '%s' or parent_mid = '%s' ) limit 1", intval(local_channel()), @@ -75,13 +76,16 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto=' $handles = $recip_handle . ';' . $sender_handle; + if($subject) + $nsubject = str_rot47(base64url_encode($subject)); + $r = q("insert into conv (uid,guid,creator,created,updated,subject,recips) values(%d, '%s', '%s', '%s', '%s', '%s', '%s') ", intval(local_channel()), dbesc($conv_guid), dbesc($sender_handle), dbesc(datetime_convert()), dbesc(datetime_convert()), - dbesc($subject), + dbesc($nsubject), dbesc($handles) ); @@ -163,19 +167,18 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto=' $jattach = (($attachments) ? json_encode($attachments) : ''); - $key = get_config('system','pubkey'); if($subject) - $subject = json_encode(crypto_encapsulate($subject,$key)); + $subject = str_rot47(base64url_encode($subject)); if($body) - $body = json_encode(crypto_encapsulate($body,$key)); + $body = str_rot47(base64url_encode($body)); - $r = q("INSERT INTO mail ( account_id, convid, mail_flags, channel_id, from_xchan, to_xchan, title, body, attach, mid, parent_mid, created, expires ) + $r = q("INSERT INTO mail ( account_id, convid, mail_obscured, channel_id, from_xchan, to_xchan, title, body, attach, mid, parent_mid, created, expires ) VALUES ( %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", intval($channel['channel_account_id']), intval($convid), - intval(MAIL_OBSCURED), + intval(1), intval($channel['channel_id']), dbesc($channel['channel_hash']), dbesc($recipient), @@ -213,6 +216,12 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto=' intval($channel['channel_id']), dbesc('<' . $channel['channel_hash'] . '>') ); + $r = q("UPDATE attach SET allow_cid = '%s' WHERE hash = '%s' AND is_photo = 1 and uid = %d and allow_cid = '%s'", + dbesc('<' . $recipient . '>'), + dbesc($image_uri), + intval($channel['channel_id']), + dbesc('<' . $channel['channel_hash'] . '>') + ); } } @@ -242,6 +251,8 @@ function private_messages_list($uid, $mailbox = '', $start = 0, $numitems = 0) { $where = ''; $limit = ''; + $t0 = dba_timer(); + if($numitems) $limit = " LIMIT " . intval($numitems) . " OFFSET " . intval($start); @@ -251,18 +262,30 @@ function private_messages_list($uid, $mailbox = '', $start = 0, $numitems = 0) { ); if(! $x) return array(); - if($mailbox === 'inbox') - $where = " and sender_xchan != '" . dbesc($x[0]['channel_hash']) . "' "; - elseif($mailbox === 'outbox') - $where = " and sender_xchan = '" . dbesc($x[0]['channel_hash']) . "' "; + + $channel_hash = dbesc($x[0]['channel_hash']); + $local_channel = intval(local_channel()); + + switch($mailbox) { + + case 'inbox': + $sql = "SELECT * FROM mail WHERE channel_id = $local_channel AND from_xchan != '$channel_hash' ORDER BY created DESC $limit"; + break; + + case 'outbox': + $sql = "SELECT * FROM mail WHERE channel_id = $local_channel AND from_xchan = '$channel_hash' ORDER BY created DESC $limit"; + break; + + case 'combined': + $sql = "SELECT * FROM ( SELECT * FROM mail WHERE channel_id = $local_channel ORDER BY created DESC $limit ) AS temp_table GROUP BY parent_mid ORDER BY created DESC"; + break; + + } + } - // For different orderings, consider applying usort on the results. We thought of doing that - // inside this function or having some preset sorts, but don't wish to limit app developers. - - $r = q("SELECT * from mail WHERE channel_id = %d $where order by created desc $limit", - intval(local_channel()) - ); + $r = q($sql); + if(! $r) { return array(); } @@ -282,13 +305,12 @@ function private_messages_list($uid, $mailbox = '', $start = 0, $numitems = 0) { foreach($r as $k => $rr) { $r[$k]['from'] = find_xchan_in_array($rr['from_xchan'],$c); $r[$k]['to'] = find_xchan_in_array($rr['to_xchan'],$c); - $r[$k]['seen'] = (($rr['mail_flags'] & MAIL_SEEN) ? 1 : 0); - if($r[$k]['mail_flags'] & MAIL_OBSCURED) { - $key = get_config('system','prvkey'); + $r[$k]['seen'] = intval($rr['mail_seen']); + if(intval($r[$k]['mail_obscured'])) { if($r[$k]['title']) - $r[$k]['title'] = crypto_unencapsulate(json_decode_plus($r[$k]['title']),$key); + $r[$k]['title'] = base64url_decode(str_rot47($r[$k]['title'])); if($r[$k]['body']) - $r[$k]['body'] = crypto_unencapsulate(json_decode_plus($r[$k]['body']),$key); + $r[$k]['body'] = base64url_decode(str_rot47($r[$k]['body'])); } } @@ -322,19 +344,17 @@ function private_messages_fetch_message($channel_id, $messageitem_id, $updatesee foreach($messages as $k => $message) { $messages[$k]['from'] = find_xchan_in_array($message['from_xchan'],$c); $messages[$k]['to'] = find_xchan_in_array($message['to_xchan'],$c); - if($messages[$k]['mail_flags'] & MAIL_OBSCURED) { - $key = get_config('system','prvkey'); + if(intval($messages[$k]['mail_obscured'])) { if($messages[$k]['title']) - $messages[$k]['title'] = crypto_unencapsulate(json_decode_plus($messages[$k]['title']),$key); + $messages[$k]['title'] = base64url_decode(str_rot47($messages[$k]['title'])); if($messages[$k]['body']) - $messages[$k]['body'] = crypto_unencapsulate(json_decode_plus($messages[$k]['body']),$key); + $messages[$k]['body'] = base64url_decode(str_rot47($messages[$k]['body'])); } } + if($updateseen) { - $r = q("UPDATE `mail` SET mail_flags = (mail_flags | %d) where not (mail_flags & %d)>0 and id = %d AND channel_id = %d", - intval(MAIL_SEEN), - intval(MAIL_SEEN), + $r = q("UPDATE `mail` SET mail_seen = 1 where mail_seen = 0 and id = %d AND channel_id = %d", dbesc($messageitem_id), intval($channel_id) ); @@ -410,20 +430,18 @@ function private_messages_fetch_conversation($channel_id, $messageitem_id, $upda foreach($messages as $k => $message) { $messages[$k]['from'] = find_xchan_in_array($message['from_xchan'],$c); $messages[$k]['to'] = find_xchan_in_array($message['to_xchan'],$c); - if($messages[$k]['mail_flags'] & MAIL_OBSCURED) { - $key = get_config('system','prvkey'); + if(intval($messages[$k]['mail_obscured'])) { if($messages[$k]['title']) - $messages[$k]['title'] = crypto_unencapsulate(json_decode_plus($messages[$k]['title']),$key); + $messages[$k]['title'] = base64url_decode(str_rot47($messages[$k]['title'])); if($messages[$k]['body']) - $messages[$k]['body'] = crypto_unencapsulate(json_decode_plus($messages[$k]['body']),$key); + $messages[$k]['body'] = base64url_decode(str_rot47($messages[$k]['body'])); } } + if($updateseen) { - $r = q("UPDATE `mail` SET mail_flags = (mail_flags | %d) where not (mail_flags & %d)>0 and parent_mid = '%s' AND channel_id = %d", - intval(MAIL_SEEN), - intval(MAIL_SEEN), + $r = q("UPDATE `mail` SET mail_seen = 1 where mail_seen = 0 and parent_mid = '%s' AND channel_id = %d", dbesc($r[0]['parent_mid']), intval($channel_id) ); @@ -431,4 +449,4 @@ function private_messages_fetch_conversation($channel_id, $messageitem_id, $upda return $messages; -}
\ No newline at end of file +} diff --git a/include/nav.php b/include/nav.php index 77287c021..1630c4731 100644 --- a/include/nav.php +++ b/include/nav.php @@ -30,14 +30,9 @@ EOT; intval($channel['channel_id']) ); - $chans = q("select channel_name, channel_id from channel where channel_account_id = %d and not ( channel_pageflags & %d )>0 order by channel_name ", - intval(get_account_id()), - intval(PAGE_REMOVED) + $chans = q("select channel_name, channel_id from channel where channel_account_id = %d and channel_removed = 0 order by channel_name ", + intval(get_account_id()) ); - - - - } elseif(remote_channel()) $observer = $a->get_observer(); @@ -99,9 +94,8 @@ EOT; require_once('include/chat.php'); $has_chats = chatroom_list_count(local_channel()); - if($has_chats) { - $nav['usermenu'][] = Array('chat/' . $channel['channel_address'],t('Chat'),"",t('Your chatrooms'),'chat_nav_btn'); - } + $nav['usermenu'][] = Array('chat/' . $channel['channel_address'] . (($has_chats) ? '' : '/new'), t('Chat'),"",t('Your chatrooms'),'chat_nav_btn'); + require_once('include/menu.php'); $has_bookmarks = menu_list_count(local_channel(),'',MENU_BOOKMARK) + menu_list_count(local_channel(),'',MENU_SYSTEM|MENU_BOOKMARK); @@ -162,7 +156,7 @@ EOT; $nav['apps'] = array('apps', t('Apps'), "", t('Applications, utilities, links, games'),'apps_nav_btn'); - $nav['search'] = array('search', t('Search'), "", t('Search site content')); + $nav['search'] = array('search', t('Search'), "", t('Search site @name, #tag, ?docs, content')); $nav['directory'] = array('directory', t('Directory'), "", t('Channel Directory'),'directory_nav_btn'); @@ -177,8 +171,8 @@ EOT; if(local_channel()) { - $nav['network'] = array('network', t('Matrix'), "", t('Your matrix'),'network_nav_btn'); - $nav['network']['mark'] = array('', t('Mark all matrix notifications seen'), '',''); + $nav['network'] = array('network', t('Grid'), "", t('Your grid'),'network_nav_btn'); + $nav['network']['mark'] = array('', t('Mark all grid notifications seen'), '',''); $nav['home'] = array('channel/' . $channel['channel_address'], t('Channel Home'), "", t('Channel home'),'home_nav_btn'); $nav['home']['mark'] = array('', t('Mark all channel notifications seen'), '',''); @@ -191,11 +185,11 @@ EOT; $nav['notifications']['all']=array('notifications/system', t('See all notifications'), "", ""); $nav['notifications']['mark'] = array('', t('Mark all system notifications seen'), '',''); - $nav['messages'] = array('message', t('Mail'), "", t('Private mail'),'mail_nav_btn'); - $nav['messages']['all']=array('message', t('See all private messages'), "", ""); + $nav['messages'] = array('mail/combined', t('Mail'), "", t('Private mail'),'mail_nav_btn'); + $nav['messages']['all']=array('mail/combined', t('See all private messages'), "", ""); $nav['messages']['mark'] = array('', t('Mark all private messages seen'), '',''); - $nav['messages']['inbox'] = array('message', t('Inbox'), "", t('Inbox')); - $nav['messages']['outbox']= array('message/sent', t('Outbox'), "", t('Outbox')); + $nav['messages']['inbox'] = array('mail/inbox', t('Inbox'), "", t('Inbox')); + $nav['messages']['outbox']= array('mail/outbox', t('Outbox'), "", t('Outbox')); $nav['messages']['new'] = array('mail/new', t('New Message'), "", t('New Message')); @@ -249,7 +243,7 @@ $powered_by = ''; '$localuser' => local_channel(), '$sel' => $a->nav_sel, '$powered_by' => $powered_by, - '$help' => t('@name, #tag, content'), + '$help' => t('@name, #tag, ?doc, content'), '$pleasewait' => t('Please wait...') )); diff --git a/include/network.php b/include/network.php index d9546a074..41e1ff37c 100644 --- a/include/network.php +++ b/include/network.php @@ -1035,7 +1035,7 @@ function discover_by_url($url,$arr = null) { dbesc(datetime_convert()) ); - $photos = import_profile_photo($photo,$guid); + $photos = import_xchan_photo($photo,$guid); $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", dbesc(datetime_convert()), dbesc($photos[0]), @@ -1053,21 +1053,30 @@ function discover_by_webbie($webbie) { $webbie = strtolower($webbie); - $x = webfinger_rfc7033($webbie); + $x = webfinger_rfc7033($webbie,true); if($x && array_key_exists('links',$x) && $x['links']) { foreach($x['links'] as $link) { if(array_key_exists('rel',$link) && $link['rel'] == 'http://purl.org/zot/protocol') { logger('discover_by_webbie: zot found for ' . $webbie, LOGGER_DEBUG); - $z = z_fetch_url($link['href']); - if($z['success']) { - $j = json_decode($z['body'],true); - $i = import_xchan($j); - return true; + if(array_key_exists('zot',$x) && $x['zot']['success']) + $i = import_xchan($x['zot']); + else { + $z = z_fetch_url($link['href']); + if($z['success']) { + $j = json_decode($z['body'],true); + $i = import_xchan($j); + return true; + } } } } } + $arr = array('address' => $webbie, 'success' => false); + call_hooks('discover_by_webbie', $arr); + if($arr['success']) + return true; + $result = array(); $network = null; $diaspora = false; @@ -1132,12 +1141,32 @@ function discover_by_webbie($webbie) { if($hcard) { $vcard = scrape_vcard($hcard); $vcard['nick'] = substr($webbie,0,strpos($webbie,'@')); + if(! $vcard['fn']) + $vcard['fn'] = $webbie; } $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($webbie) + dbesc($addr) ); - if(! $r) { + + /** + * + * Diaspora communications are notoriously unreliable and receiving profile update messages (indeed any messages) + * are pretty much random luck. We'll check the timestamp of the xchan_name_date at a higher level and refresh + * this record once a month; because if you miss a profile update message and they update their profile photo or name + * you're otherwise stuck with stale info until they change their profile again - which could be years from now. + * + */ + + if($r) { + $r = q("update xchan set xchan_name = '%s', xchan_network = '%s', xchan_name_date = '%s' where xchan_hash = '%s' limit 1", + dbesc($vcard['fn']), + dbesc($network), + dbesc(datetime_convert()), + dbesc($addr) + ); + } + else { $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_pubkey, xchan_addr, xchan_url, xchan_name, xchan_network, xchan_instance_url, xchan_name_date ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ", dbesc($addr), @@ -1158,7 +1187,7 @@ function discover_by_webbie($webbie) { if(! $r) { - $r = q("insert into hubloc ( hubloc_guid, hubloc_hash, hubloc_addr, hubloc_network, hubloc_url, hubloc_host, hubloc_callback, hubloc_updated, hubloc_flags ) values ('%s','%s','%s','%s','%s','%s','%s','%s', %d)", + $r = q("insert into hubloc ( hubloc_guid, hubloc_hash, hubloc_addr, hubloc_network, hubloc_url, hubloc_host, hubloc_callback, hubloc_updated, hubloc_primary ) values ('%s','%s','%s','%s','%s','%s','%s','%s', 1)", dbesc($guid), dbesc($addr), dbesc($addr), @@ -1166,11 +1195,10 @@ function discover_by_webbie($webbie) { dbesc(trim($diaspora_base,'/')), dbesc($hostname), dbesc($notify), - dbescdate(datetime_convert()), - intval(HUBLOC_FLAGS_PRIMARY) + dbescdate(datetime_convert()) ); } - $photos = import_profile_photo($vcard['photo'],$addr); + $photos = import_xchan_photo($vcard['photo'],$addr); $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", dbescdate(datetime_convert('UTC','UTC',$arr['photo_updated'])), dbesc($photos[0]), @@ -1258,7 +1286,7 @@ LSIeXnd14lQYK/uxW/8cTFjcmddsKxeXysoQxbSa9VdDK+KkpZdgYXYrTTofXs6v+ } -function webfinger_rfc7033($webbie) { +function webfinger_rfc7033($webbie,$zot = false) { if(! strpos($webbie,'@')) @@ -1268,7 +1296,7 @@ function webfinger_rfc7033($webbie) { $resource = 'acct:' . $webbie; - $s = z_fetch_url('https://' . $rhs . '/.well-known/webfinger?resource=' . $resource); + $s = z_fetch_url('https://' . $rhs . '/.well-known/webfinger?f=&resource=' . $resource . (($zot) ? '&zot=1' : '')); if($s['success']) $j = json_decode($s['body'],true); diff --git a/include/notifier.php b/include/notifier.php index ecd2ac86f..db1aa9690 100644 --- a/include/notifier.php +++ b/include/notifier.php @@ -100,10 +100,9 @@ function notifier_run($argv, $argc){ // Get the recipient $r = q("select abook.*, hubloc.* from abook left join hubloc on hubloc_hash = abook_xchan - where abook_id = %d and not ( abook_flags & %d ) > 0 + where abook_id = %d and abook_self = 0 and not (hubloc_flags & %d) > 0 and not (hubloc_status & %d) > 0 limit 1", intval($item_id), - intval(ABOOK_FLAG_SELF), intval(HUBLOC_FLAGS_DELETED), intval(HUBLOC_OFFLINE) ); @@ -114,11 +113,9 @@ function notifier_run($argv, $argc){ intval($r[0]['abook_channel']) ); if($s) { - if($r[0]['hubloc_network'] === 'diaspora' || $r[0]['hubloc_network'] === 'friendica-over-diaspora') { - require_once('include/diaspora.php'); - diaspora_share($s[0],$r[0]); - } - else { + $perm_update = array('sender' => $s[0], 'recipient' => $r[0], 'success' => false); + call_hooks('permissions_update',$perm_update); + if(! $perm_update['success']) { // send a refresh message to each hub they have registered here $h = q("select * from hubloc where hubloc_hash = '%s' and not (hubloc_flags & %d) > 0 and not (hubloc_status & %d) > 0", @@ -228,11 +225,9 @@ function notifier_run($argv, $argc){ $normal_mode = false; $expire = true; - $items = q("SELECT * FROM item WHERE uid = %d AND ( item_flags & %d )>0 - AND ( item_restrict & %d )>0 AND `changed` > %s - INTERVAL %s", + $items = q("SELECT * FROM item WHERE uid = %d AND item_wall = 1 + AND item_deleted = 1 AND `changed` > %s - INTERVAL %s", intval($item_id), - intval(ITEM_WALL), - intval(ITEM_DELETED), db_utcnow(), db_quoteinterval('10 MINUTE') ); $uid = $item_id; @@ -338,19 +333,22 @@ function notifier_run($argv, $argc){ $target_item = $r[0]; $deleted_item = false; - if($target_item['item_restrict'] & ITEM_DELETED) { + if(intval($target_item['item_deleted'])) { logger('notifier: target item ITEM_DELETED', LOGGER_DEBUG); $deleted_item = true; } - if(strpos($target_item['postopts'],'nodeliver') !== false) { - logger('notifier: target item is undeliverable', LOGGER_DEBUG); + if(intval($target_item['item_type']) != ITEM_TYPE_POST) { + logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG); + return; + } + if(intval($target_item['item_unpublished']) || intval($target_item['item_delayed_publish'])) { + logger('notifier: target item not published, so not forwardable', LOGGER_DEBUG); return; } - $unforwardable = ITEM_UNPUBLISHED|ITEM_DELAYED_PUBLISH|ITEM_WEBPAGE|ITEM_BUILDBLOCK|ITEM_PDL; - if($target_item['item_restrict'] & $unforwardable) { - logger('notifier: target item not forwardable: flags ' . $target_item['item_restrict'], LOGGER_DEBUG); + if(strpos($target_item['postopts'],'nodeliver') !== false) { + logger('notifier: target item is undeliverable', LOGGER_DEBUG); return; } @@ -407,10 +405,7 @@ function notifier_run($argv, $argc){ // flag on comments for an extended period. So we'll also call comment_local_origin() which looks at // the hostname in the message_id and provides a second (fallback) opinion. - $relay_to_owner = (((! $top_level_post) && ($target_item['item_flags'] & ITEM_ORIGIN) && comment_local_origin($target_item)) - ? true - : false - ); + $relay_to_owner = (((! $top_level_post) && (intval($target_item['item_origin'])) && comment_local_origin($target_item)) ? true : false); @@ -421,11 +416,10 @@ function notifier_run($argv, $argc){ logger('notifier: relay_to_owner: ' . (($relay_to_owner) ? 'true' : 'false'), LOGGER_DATA); logger('notifier: top_level_post: ' . (($top_level_post) ? 'true' : 'false'), LOGGER_DATA); - logger('notifier: target_item_flags: ' . $target_item['item_flags'] . ' ' . (($target_item['item_flags'] & ITEM_ORIGIN ) ? 'true' : 'false'), LOGGER_DATA); // tag_deliver'd post which needs to be sent back to the original author - if(($cmd === 'uplink') && ($parent_item['item_flags'] & ITEM_UPLINK) && (! $top_level_post)) { + if(($cmd === 'uplink') && intval($parent_item['item_uplink']) && (! $top_level_post)) { logger('notifier: uplink'); $uplink = true; } @@ -446,7 +440,7 @@ function notifier_run($argv, $argc){ // if our parent is a tag_delivery recipient, uplink to the original author causing // a delivery fork. - if(($parent_item['item_flags'] & ITEM_UPLINK) && (! $top_level_post) && ($cmd !== 'uplink')) { + if(intval($parent_item['item_uplink']) && (! $top_level_post) && ($cmd !== 'uplink')) { logger('notifier: uplinking this item'); proc_run('php','include/notifier.php','uplink',$item_id); } @@ -459,7 +453,7 @@ function notifier_run($argv, $argc){ // don't send deletions onward for other people's stuff // TODO verify this is needed - copied logic from same place in old code - if(($target_item['item_restrict'] & ITEM_DELETED) && (!($target_item['item_flags'] & ITEM_WALL))) { + if(intval($target_item['item_deleted']) && (! intval($target_item['item_wall']))) { logger('notifier: ignoring delete notification for non-wall item'); return; } @@ -492,20 +486,6 @@ function notifier_run($argv, $argc){ if($details) { foreach($details as $d) { - // If the recipient is federated from a traditional network they won't be able to - // handle nomadic identity. If we're publishing from a site that they aren't - // directly connected with, ignore them. - - // FIXME: make sure we run through a notifier loop on the hub they're connected - // with if this post comes in from a different hub - so that we will deliver to them. - - // On the down side, these channels will stop working if the hub they connected with - // goes down permanently, as they are (doh) not nomadic. - - if(($d['xchan_instance_url']) && ($d['xchan_instance_url'] != z_root())) - continue; - - $recip_list[] = $d['xchan_addr'] . ' (' . $d['xchan_hash'] . ')'; if($private) $env_recips[] = array('guid' => $d['xchan_guid'],'guid_sig' => $d['xchan_guid_sig'],'hash' => $d['xchan_hash']); @@ -532,34 +512,10 @@ function notifier_run($argv, $argc){ // Now we have collected recipients (except for external mentions, FIXME) // Let's reduce this to a set of hubs. - logger('notifier: hub choice: ' . intval($relay_to_owner) . ' ' . intval($private) . ' ' . $cmd, LOGGER_DEBUG); - - // FIXME: I think we need to remove the private bit or this clause will never execute. Needs more coffee to think it through. - // We may in fact have to send it to clones in case the one we pick recently died. - - if($relay_to_owner && (! $private) && ($cmd !== 'relay')) { - - // If sending a followup to the post owner, only send it to one channel clone - to avoid race conditions. - // In this case we'll pick the most recently contacted hub, as their primary might be down and the most - // recently contacted has the best chance of being alive. - - // For private posts or uplinks we have to do things differently as only the sending clone will have the recipient list. - // We have to send to all clone channels of the owner to find out who has the definitive list. Posts with - // item_private set (but no ACL list) will return empty recipients (except for the sender and owner) in - // collect_recipients() above. The end result is we should get only one delivery per delivery chain if we - // aren't the owner or author. - - - $r = q("select hubloc_guid, hubloc_url, hubloc_sitekey, hubloc_network, hubloc_flags, hubloc_callback, hubloc_host from hubloc - where hubloc_hash in (" . implode(',',$recipients) . ") order by hubloc_connected desc limit 1"); - } - else { - $r = q("select hubloc_guid, hubloc_url, hubloc_sitekey, hubloc_network, hubloc_flags, hubloc_callback, hubloc_host from hubloc - where hubloc_hash in (" . implode(',',$recipients) . ") and not (hubloc_flags & %d) > 0 and not (hubloc_status & %d) > 0", - intval(HUBLOC_FLAGS_DELETED), - intval(HUBLOC_OFFLINE) - ); - } + $r = q("select * from hubloc where hubloc_hash in (" . implode(',',$recipients) . ") + and hubloc_error = 0 and hubloc_deleted = 0" + ); + if(! $r) { logger('notifier: no hubs'); @@ -568,6 +524,15 @@ function notifier_run($argv, $argc){ $hubs = $r; + $dead_hubs = array(); + + $dh = q("select site_url from site where site_dead = 1"); + if(dh) { + foreach($dh as $dead) { + $dead_hubs[] = $dead['site_url']; + } + } + /** * Reduce the hubs to those that are unique. For zot hubs, we need to verify uniqueness by the sitekey, since it may have been @@ -583,6 +548,11 @@ function notifier_run($argv, $argc){ foreach($hubs as $hub) { + if(in_array($hub['hubloc_url'],$dead_hubs)) { + logger('skipping dead hub: ' . $hub['hubloc_url'], LOGGER_DEBUG); + continue; + } + if($hub['hubloc_network'] == 'zot') { if(! in_array($hub['hubloc_sitekey'],$keys)) { $hublist[] = $hub['hubloc_host']; @@ -609,22 +579,13 @@ function notifier_run($argv, $argc){ if($deliveries_per_process <= 0) $deliveries_per_process = 1; - $deliver = array(); + $deliveries = array(); foreach($dhubs as $hub) { - if($hub['hubloc_network'] === 'diaspora' || $hub['hubloc_network'] === 'friendica-over-diaspora') { - if(! get_config('system','diaspora_enabled')) - continue; - - // allow this to be set per message + if($hub['hubloc_network'] !== 'zot') { - if(strpos($target_item['postopts'],'nodspr') !== false) - continue; - - require_once('include/diaspora.php'); - - diaspora_process_outbound(array( + $narr = array( 'channel' => $channel, 'env_recips' => $env_recips, 'recipients' => $recipients, @@ -644,14 +605,20 @@ function notifier_run($argv, $argc){ 'request' => $request, 'normal_mode' => $normal_mode, 'packet_type' => $packet_type, - 'walltowall' => $walltowall - )); + 'walltowall' => $walltowall, + 'queued' => array() + ); + + call_hooks('notifier_hub',$narr); + if($narr['queued']) { + foreach($narr['queued'] as $pq) + $deliveries[] = $pq; + } continue; } - // default: zot protocol @@ -700,28 +667,51 @@ function notifier_run($argv, $argc){ dbesc($n), dbesc(json_encode($encoded_item)) ); + // only create delivery reports for normal undeleted items + if(array_key_exists('postopts',$target_item) && (! $target_item['item_deleted'])) { + q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan, dreport_queue ) values ( '%s','%s','%s','%s','%s','%s','%s' ) ", + dbesc($target_item['mid']), + dbesc($hub['hubloc_host']), + dbesc($hub['hubloc_host']), + dbesc('queued'), + dbesc(datetime_convert()), + dbesc($channel['channel_hash']), + dbesc($hash) + ); + } } - $deliver[] = $hash; - if(count($deliver) >= $deliveries_per_process) { - proc_run('php','include/deliver.php',$deliver); - $deliver = array(); - if($interval) - @time_sleep_until(microtime(true) + (float) $interval); + $deliveries[] = $hash; + } + + if($normal_mode) { + $x = q("select * from hook where hook = 'notifier_normal'"); + if($x) + proc_run('php','deliver_hooks.php', $target_item['id']); + } + + if($deliveries) { + $deliver = array(); + + foreach($deliveries as $d) { + + $deliver[] = $d; + + if(count($deliver) >= $deliveries_per_process) { + proc_run('php','include/deliver.php',$deliver); + $deliver = array(); + if($interval) + @time_sleep_until(microtime(true) + (float) $interval); + } } } // catch any stragglers - if(count($deliver)) { + if($deliver) proc_run('php','include/deliver.php',$deliver); - } logger('notifier: basic loop complete.', LOGGER_DEBUG); - - if($normal_mode) - call_hooks('notifier_normal',$target_item); - call_hooks('notifier_end',$target_item); diff --git a/include/notify.php b/include/notify.php index eef838664..2b032b56b 100644 --- a/include/notify.php +++ b/include/notify.php @@ -5,9 +5,6 @@ function format_notification($item) { $ret = ''; -// return array(); - - require_once('include/conversation.php'); // Call localize_item with the "brief" flag to get a one line status for activities. @@ -19,7 +16,7 @@ function format_notification($item) { $itemem_text = $item['localize']; } else { - $itemem_text = (($item['item_flags'] & ITEM_THREAD_TOP) + $itemem_text = (($item['item_thread_top']) ? t('created a new post') : sprintf( t('commented on %s\'s post'), $item['owner']['xchan_name'])); } diff --git a/include/oembed.php b/include/oembed.php index 0628afaa9..e50d34c7d 100755 --- a/include/oembed.php +++ b/include/oembed.php @@ -2,6 +2,35 @@ function oembed_replacecb($matches){ $embedurl=$matches[1]; + + // implements a personal embed white/black list for logged in members + if(local_channel()) { + if(($x = get_pconfig(local_channel(),'system','embed_deny'))) { + $l = explode("\n",$x); + if($l) { + foreach($l as $ll) { + if(trim($ll) && strpos($embedurl,trim($ll)) !== false) + return '<a href="' . $embedurl . '">' . $embedurl . '</a>'; + } + } + } + if(($x = get_pconfig(local_channel(),'system','embed_allow'))) { + $found = false; + $l = explode("\n",$x); + if($l) { + foreach($l as $ll) { + if(trim($ll) && strpos($embedurl,trim($ll)) !== false) { + $found = true; + break; + } + } + } + if(! $found) { + return '<a href="' . $embedurl . '">' . $embedurl . '</a>'; + } + } + } + $j = oembed_fetch_url($embedurl); $s = oembed_format_object($j); return $s; @@ -95,7 +124,8 @@ function oembed_fetch_url($embedurl){ Cache::set($a->videowidth . $embedurl,$txt); } - + + $j = json_decode($txt); $j->embedurl = $embedurl; return $j; diff --git a/include/onedirsync.php b/include/onedirsync.php index de8dab92d..ce516da9d 100644 --- a/include/onedirsync.php +++ b/include/onedirsync.php @@ -41,7 +41,7 @@ function onedirsync_run($argv, $argc){ intval(UPDATE_FLAGS_UPDATED) ); if($x) { - $y = q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 and ud_date < '%s' ", + $y = q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 and ud_date != '%s'", intval(UPDATE_FLAGS_UPDATED), dbesc($r[0]['ud_addr']), intval(UPDATE_FLAGS_UPDATED), diff --git a/include/onepoll.php b/include/onepoll.php index 66b000934..fedeb1e95 100644 --- a/include/onepoll.php +++ b/include/onepoll.php @@ -28,13 +28,9 @@ function onepoll_run($argv, $argc){ $contacts = q("SELECT abook.*, xchan.*, account.* FROM abook LEFT JOIN account on abook_account = account_id left join xchan on xchan_hash = abook_xchan where abook_id = %d - AND (( abook_flags & %d )>0 OR ( abook_flags = %d )) - AND NOT ( abook_flags & %d )>0 + and abook_pending = 0 and abook_archived = 0 and abook_blocked = 0 and abook_ignored = 0 AND (( account_flags = %d ) OR ( account_flags = %d )) limit 1", intval($contact_id), - intval(ABOOK_FLAG_HIDDEN|ABOOK_FLAG_PENDING|ABOOK_FLAG_UNCONNECTED|ABOOK_FLAG_FEED), - intval(0), - intval(ABOOK_FLAG_ARCHIVED|ABOOK_FLAG_BLOCKED|ABOOK_FLAG_IGNORED), intval(ACCOUNT_OK), intval(ACCOUNT_UNVERIFIED) ); diff --git a/include/permissions.php b/include/permissions.php index f63c6da18..a8e761f87 100644 --- a/include/permissions.php +++ b/include/permissions.php @@ -25,9 +25,8 @@ function get_perms() { // Read only permissions 'view_stream' => array('channel_r_stream', intval(PERMS_R_STREAM), true, t('Can view my normal stream and posts'), ''), 'view_profile' => array('channel_r_profile', intval(PERMS_R_PROFILE), true, t('Can view my default channel profile'), ''), - 'view_photos' => array('channel_r_photos', intval(PERMS_R_PHOTOS), true, t('Can view my photo albums'), ''), 'view_contacts' => array('channel_r_abook', intval(PERMS_R_ABOOK), true, t('Can view my connections'), ''), - 'view_storage' => array('channel_r_storage', intval(PERMS_R_STORAGE), true, t('Can view my file storage'), ''), + 'view_storage' => array('channel_r_storage', intval(PERMS_R_STORAGE), true, t('Can view my file storage and photos'), ''), 'view_pages' => array('channel_r_pages', intval(PERMS_R_PAGES), true, t('Can view my webpages'), ''), // Write permissions @@ -35,12 +34,11 @@ function get_perms() { 'post_wall' => array('channel_w_wall', intval(PERMS_W_WALL), false, t('Can post on my channel page ("wall")'), ''), 'post_comments' => array('channel_w_comment', intval(PERMS_W_COMMENT), false, t('Can comment on or like my posts'), ''), 'post_mail' => array('channel_w_mail', intval(PERMS_W_MAIL), false, t('Can send me private mail messages'), ''), - 'post_photos' => array('channel_w_photos', intval(PERMS_W_PHOTOS), false, t('Can post photos to my photo albums'), ''), 'post_like' => array('channel_w_like', intval(PERMS_W_LIKE), false, t('Can like/dislike stuff'), t('Profiles and things other than posts/comments')), 'tag_deliver' => array('channel_w_tagwall', intval(PERMS_W_TAGWALL), false, t('Can forward to all my channel contacts via post @mentions'), t('Advanced - useful for creating group forum channels')), 'chat' => array('channel_w_chat', intval(PERMS_W_CHAT), false, t('Can chat with me (when available)'), t('')), - 'write_storage' => array('channel_w_storage', intval(PERMS_W_STORAGE), false, t('Can write to my file storage'), ''), + 'write_storage' => array('channel_w_storage', intval(PERMS_W_STORAGE), false, t('Can write to my file storage and photos'), ''), 'write_pages' => array('channel_w_pages', intval(PERMS_W_PAGES), false, t('Can edit my webpages'), ''), 'republish' => array('channel_a_republish', intval(PERMS_A_REPUBLISH), false, t('Can source my public posts in derived channels'), t('Somewhat advanced - very useful in open communities')), @@ -113,11 +111,10 @@ function get_all_perms($uid, $observer_xchan, $internal_use = true) { } if(! $abook_checked) { - $x = q("select abook_my_perms, abook_flags, xchan_network from abook left join xchan on abook_xchan = xchan_hash - where abook_channel = %d and abook_xchan = '%s' and not ( abook_flags & %d )>0 limit 1", + $x = q("select abook_my_perms, abook_blocked, abook_ignored, abook_pending, xchan_network from abook left join xchan on abook_xchan = xchan_hash + where abook_channel = %d and abook_xchan = '%s' and abook_self = 0 limit 1", intval($uid), - dbesc($observer_xchan), - intval(ABOOK_FLAG_SELF) + dbesc($observer_xchan) ); if(! $x) { // not in address book, see if they've got an xchan @@ -131,7 +128,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)) { + if(($x) && intval($x[0]['abook_blocked'])) { $ret[$perm_name] = false; continue; } @@ -139,7 +136,7 @@ function get_all_perms($uid, $observer_xchan, $internal_use = true) { // Check if this is a write permission and they are being ignored // This flag is only visible internally. - if(($x) && ($internal_use) && (! $global_perms[$perm_name][2]) && ($x[0]['abook_flags'] & ABOOK_FLAG_IGNORED)) { + if(($x) && ($internal_use) && (! $global_perms[$perm_name][2]) && intval($x[0]['abook_ignored'])) { $ret[$perm_name] = false; continue; } @@ -218,7 +215,7 @@ function get_all_perms($uid, $observer_xchan, $internal_use = true) { continue; } - if($x[0]['abook_flags'] & ABOOK_FLAG_PENDING) { + if(intval($x[0]['abook_pending'])) { $ret[$perm_name] = false; continue; } @@ -300,19 +297,18 @@ function perm_is_allowed($uid, $observer_xchan, $permission) { if($r[0][$channel_perm] & PERMS_AUTHED) return true; - $x = q("select abook_my_perms, abook_flags, xchan_network from abook left join xchan on abook_xchan = xchan_hash - where abook_channel = %d and abook_xchan = '%s' and not ( abook_flags & %d )>0 limit 1", + $x = q("select abook_my_perms, abook_blocked, abook_ignored, abook_pending, xchan_network from abook left join xchan on abook_xchan = xchan_hash + where abook_channel = %d and abook_xchan = '%s' and abook_self = 0 limit 1", intval($uid), - dbesc($observer_xchan), - intval(ABOOK_FLAG_SELF) + dbesc($observer_xchan) ); // If they're blocked - they can't read or write - if(($x) && ($x[0]['abook_flags'] & ABOOK_FLAG_BLOCKED)) + if(($x) && intval($x[0]['abook_blocked'])) return false; - if(($x) && (! $global_perms[$permission][2]) && ($x[0]['abook_flags'] & ABOOK_FLAG_IGNORED)) + if(($x) && (! $global_perms[$permission][2]) && intval($x[0]['abook_ignored'])) return false; if(! $x) { @@ -374,7 +370,7 @@ function perm_is_allowed($uid, $observer_xchan, $permission) { return true; } - if($x[0]['abook_flags'] & ABOOK_FLAG_PENDING) { + if(intval($x[0]['abook_pending'])) { return false; } @@ -498,7 +494,6 @@ function site_default_perms() { $typical = array( 'view_stream' => PERMS_PUBLIC, 'view_profile' => PERMS_PUBLIC, - 'view_photos' => PERMS_PUBLIC, 'view_contacts' => PERMS_PUBLIC, 'view_storage' => PERMS_PUBLIC, 'view_pages' => PERMS_PUBLIC, @@ -506,7 +501,6 @@ function site_default_perms() { 'post_wall' => PERMS_SPECIFIC, 'post_comments' => PERMS_SPECIFIC, 'post_mail' => PERMS_SPECIFIC, - 'post_photos' => PERMS_SPECIFIC, 'tag_deliver' => PERMS_SPECIFIC, 'chat' => PERMS_SPECIFIC, 'write_storage' => PERMS_SPECIFIC, @@ -556,22 +550,20 @@ function get_role_perms($role) { $ret['default_collection'] = false; $ret['directory_publish'] = true; $ret['online'] = true; - $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE; - $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE; $ret['channel_r_stream'] = PERMS_PUBLIC; $ret['channel_r_profile'] = PERMS_PUBLIC; - $ret['channel_r_photos'] = PERMS_PUBLIC; $ret['channel_r_abook'] = PERMS_PUBLIC; $ret['channel_w_stream'] = PERMS_SPECIFIC; $ret['channel_w_wall'] = PERMS_SPECIFIC; $ret['channel_w_tagwall'] = PERMS_SPECIFIC; $ret['channel_w_comment'] = PERMS_SPECIFIC; $ret['channel_w_mail'] = PERMS_SPECIFIC; - $ret['channel_w_photos'] = PERMS_SPECIFIC; $ret['channel_w_chat'] = PERMS_SPECIFIC; $ret['channel_a_delegate'] = PERMS_SPECIFIC; $ret['channel_r_storage'] = PERMS_PUBLIC; @@ -588,22 +580,20 @@ function get_role_perms($role) { $ret['default_collection'] = true; $ret['directory_publish'] = true; $ret['online'] = true; - $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE; - $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE; $ret['channel_r_stream'] = PERMS_PUBLIC; $ret['channel_r_profile'] = PERMS_PUBLIC; - $ret['channel_r_photos'] = PERMS_PUBLIC; $ret['channel_r_abook'] = PERMS_PUBLIC; $ret['channel_w_stream'] = PERMS_SPECIFIC; $ret['channel_w_wall'] = PERMS_SPECIFIC; $ret['channel_w_tagwall'] = PERMS_SPECIFIC; $ret['channel_w_comment'] = PERMS_SPECIFIC; $ret['channel_w_mail'] = PERMS_SPECIFIC; - $ret['channel_w_photos'] = PERMS_SPECIFIC; $ret['channel_w_chat'] = PERMS_SPECIFIC; $ret['channel_a_delegate'] = PERMS_SPECIFIC; $ret['channel_r_storage'] = PERMS_PUBLIC; @@ -620,22 +610,20 @@ function get_role_perms($role) { $ret['default_collection'] = true; $ret['directory_publish'] = false; $ret['online'] = false; - $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE; - $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE; $ret['channel_r_stream'] = PERMS_PUBLIC; $ret['channel_r_profile'] = PERMS_PUBLIC; - $ret['channel_r_photos'] = PERMS_PUBLIC; $ret['channel_r_abook'] = PERMS_SPECIFIC; $ret['channel_w_stream'] = PERMS_SPECIFIC; $ret['channel_w_wall'] = PERMS_SPECIFIC; $ret['channel_w_tagwall'] = PERMS_SPECIFIC; $ret['channel_w_comment'] = PERMS_SPECIFIC; $ret['channel_w_mail'] = PERMS_SPECIFIC; - $ret['channel_w_photos'] = PERMS_SPECIFIC; $ret['channel_w_chat'] = PERMS_SPECIFIC; $ret['channel_a_delegate'] = PERMS_SPECIFIC; $ret['channel_r_storage'] = PERMS_PUBLIC; @@ -652,22 +640,20 @@ function get_role_perms($role) { $ret['default_collection'] = false; $ret['directory_publish'] = true; $ret['online'] = false; - $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE|PERMS_W_TAGWALL; - $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE|PERMS_W_TAGWALL; $ret['channel_r_stream'] = PERMS_PUBLIC; $ret['channel_r_profile'] = PERMS_PUBLIC; - $ret['channel_r_photos'] = PERMS_PUBLIC; $ret['channel_r_abook'] = PERMS_PUBLIC; $ret['channel_w_stream'] = PERMS_SPECIFIC; $ret['channel_w_wall'] = PERMS_SPECIFIC; $ret['channel_w_tagwall'] = PERMS_SPECIFIC; $ret['channel_w_comment'] = PERMS_SPECIFIC; $ret['channel_w_mail'] = PERMS_SPECIFIC; - $ret['channel_w_photos'] = PERMS_SPECIFIC; $ret['channel_w_chat'] = PERMS_SPECIFIC; $ret['channel_a_delegate'] = PERMS_SPECIFIC; $ret['channel_r_storage'] = PERMS_PUBLIC; @@ -684,22 +670,20 @@ function get_role_perms($role) { $ret['default_collection'] = true; $ret['directory_publish'] = true; $ret['online'] = false; - $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE|PERMS_W_TAGWALL; - $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE|PERMS_W_TAGWALL; $ret['channel_r_stream'] = PERMS_PUBLIC; $ret['channel_r_profile'] = PERMS_PUBLIC; - $ret['channel_r_photos'] = PERMS_PUBLIC; $ret['channel_r_abook'] = PERMS_PUBLIC; $ret['channel_w_stream'] = PERMS_SPECIFIC; $ret['channel_w_wall'] = PERMS_SPECIFIC; $ret['channel_w_tagwall'] = PERMS_SPECIFIC; $ret['channel_w_comment'] = PERMS_SPECIFIC; $ret['channel_w_mail'] = PERMS_SPECIFIC; - $ret['channel_w_photos'] = PERMS_SPECIFIC; $ret['channel_w_chat'] = PERMS_SPECIFIC; $ret['channel_a_delegate'] = PERMS_SPECIFIC; $ret['channel_r_storage'] = PERMS_PUBLIC; @@ -716,22 +700,20 @@ function get_role_perms($role) { $ret['default_collection'] = true; $ret['directory_publish'] = false; $ret['online'] = false; - $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE; - $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILEPERMS_R_ABOOK |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE; $ret['channel_r_stream'] = PERMS_PUBLIC; $ret['channel_r_profile'] = PERMS_SPECIFIC; - $ret['channel_r_photos'] = PERMS_SPECIFIC; $ret['channel_r_abook'] = PERMS_SPECIFIC; $ret['channel_w_stream'] = PERMS_SPECIFIC; $ret['channel_w_wall'] = PERMS_SPECIFIC; $ret['channel_w_tagwall'] = PERMS_SPECIFIC; $ret['channel_w_comment'] = PERMS_SPECIFIC; $ret['channel_w_mail'] = PERMS_SPECIFIC; - $ret['channel_w_photos'] = PERMS_SPECIFIC; $ret['channel_w_chat'] = PERMS_SPECIFIC; $ret['channel_a_delegate'] = PERMS_SPECIFIC; $ret['channel_r_storage'] = PERMS_SPECIFIC; @@ -748,22 +730,20 @@ function get_role_perms($role) { $ret['default_collection'] = false; $ret['directory_publish'] = true; $ret['online'] = false; - $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE; - $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE; $ret['channel_r_stream'] = PERMS_PUBLIC; $ret['channel_r_profile'] = PERMS_PUBLIC; - $ret['channel_r_photos'] = PERMS_PUBLIC; $ret['channel_r_abook'] = PERMS_PUBLIC; $ret['channel_w_stream'] = PERMS_SPECIFIC; $ret['channel_w_wall'] = PERMS_SPECIFIC; $ret['channel_w_tagwall'] = PERMS_SPECIFIC; $ret['channel_w_comment'] = PERMS_SPECIFIC; $ret['channel_w_mail'] = PERMS_SPECIFIC; - $ret['channel_w_photos'] = PERMS_SPECIFIC; $ret['channel_w_chat'] = PERMS_SPECIFIC; $ret['channel_a_delegate'] = PERMS_SPECIFIC; $ret['channel_r_storage'] = PERMS_PUBLIC; @@ -780,22 +760,20 @@ function get_role_perms($role) { $ret['default_collection'] = true; $ret['directory_publish'] = false; $ret['online'] = false; - $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE; - $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE; $ret['channel_r_stream'] = PERMS_PUBLIC; $ret['channel_r_profile'] = PERMS_PUBLIC; - $ret['channel_r_photos'] = PERMS_PUBLIC; $ret['channel_r_abook'] = PERMS_PUBLIC; $ret['channel_w_stream'] = PERMS_SPECIFIC; $ret['channel_w_wall'] = PERMS_SPECIFIC; $ret['channel_w_tagwall'] = PERMS_SPECIFIC; $ret['channel_w_comment'] = PERMS_SPECIFIC; $ret['channel_w_mail'] = PERMS_SPECIFIC; - $ret['channel_w_photos'] = PERMS_SPECIFIC; $ret['channel_w_chat'] = PERMS_SPECIFIC; $ret['channel_a_delegate'] = PERMS_SPECIFIC; $ret['channel_r_storage'] = PERMS_PUBLIC; @@ -812,20 +790,18 @@ function get_role_perms($role) { $ret['default_collection'] = false; $ret['directory_publish'] = true; $ret['online'] = false; - $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE; - $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE; $ret['channel_r_stream'] = PERMS_PUBLIC; $ret['channel_r_profile'] = PERMS_PUBLIC; - $ret['channel_r_photos'] = PERMS_PUBLIC; $ret['channel_r_abook'] = PERMS_PUBLIC; $ret['channel_w_stream'] = PERMS_SPECIFIC; $ret['channel_w_wall'] = PERMS_SPECIFIC; $ret['channel_w_tagwall'] = PERMS_SPECIFIC; $ret['channel_w_comment'] = PERMS_SPECIFIC; $ret['channel_w_mail'] = PERMS_SPECIFIC; - $ret['channel_w_photos'] = PERMS_SPECIFIC; $ret['channel_w_chat'] = PERMS_SPECIFIC; $ret['channel_a_delegate'] = PERMS_SPECIFIC; $ret['channel_r_storage'] = PERMS_PUBLIC; @@ -842,22 +818,20 @@ function get_role_perms($role) { $ret['default_collection'] = false; $ret['directory_publish'] = true; $ret['online'] = false; - $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + $ret['perms_follow'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT |PERMS_R_STORAGE|PERMS_W_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE|PERMS_W_TAGWALL; - $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK + $ret['perms_accept'] = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_ABOOK |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT |PERMS_R_STORAGE|PERMS_W_STORAGE|PERMS_R_PAGES|PERMS_A_REPUBLISH|PERMS_W_LIKE|PERMS_W_TAGWALL; $ret['channel_r_stream'] = PERMS_PUBLIC; $ret['channel_r_profile'] = PERMS_PUBLIC; - $ret['channel_r_photos'] = PERMS_PUBLIC; $ret['channel_r_abook'] = PERMS_PUBLIC; $ret['channel_w_stream'] = PERMS_SPECIFIC; $ret['channel_w_wall'] = PERMS_SPECIFIC; $ret['channel_w_tagwall'] = PERMS_SPECIFIC; $ret['channel_w_comment'] = PERMS_SPECIFIC; $ret['channel_w_mail'] = PERMS_SPECIFIC; - $ret['channel_w_photos'] = PERMS_SPECIFIC; $ret['channel_w_chat'] = PERMS_SPECIFIC; $ret['channel_a_delegate'] = PERMS_SPECIFIC; $ret['channel_r_storage'] = PERMS_PUBLIC; diff --git a/include/photo/photo_driver.php b/include/photo/photo_driver.php index 5d61556ab..32b9bd302 100644 --- a/include/photo/photo_driver.php +++ b/include/photo/photo_driver.php @@ -238,10 +238,12 @@ abstract class photo_driver { if(! $this->is_valid()) return FALSE; + if((! function_exists('exif_read_data')) || ($this->getType() !== 'image/jpeg')) return; $exif = @exif_read_data($filename,null,true); + if($exif) { $ort = $exif['IFD0']['Orientation']; @@ -281,7 +283,6 @@ abstract class photo_driver { break; } - // logger('exif: ' . print_r($exif,true)); return $exif; } @@ -302,7 +303,6 @@ abstract class photo_driver { $p['filename'] = (($arr['filename']) ? $arr['filename'] : ''); $p['album'] = (($arr['album']) ? $arr['album'] : ''); $p['scale'] = ((intval($arr['scale'])) ? intval($arr['scale']) : 0); - $p['photo_flags'] = ((intval($arr['photo_flags'])) ? intval($arr['photo_flags']) : 0); $p['allow_cid'] = (($arr['allow_cid']) ? $arr['allow_cid'] : ''); $p['allow_gid'] = (($arr['allow_gid']) ? $arr['allow_gid'] : ''); $p['deny_cid'] = (($arr['deny_cid']) ? $arr['deny_cid'] : ''); @@ -311,12 +311,12 @@ abstract class photo_driver { $p['edited'] = (($arr['edited']) ? $arr['edited'] : $p['created']); $p['title'] = (($arr['title']) ? $arr['title'] : ''); $p['description'] = (($arr['description']) ? $arr['description'] : ''); + $p['photo_usage'] = intval($arr['photo_usage']); + $p['os_storage'] = intval($arr['os_storage']); + $p['os_path'] = $arr['os_path']; - // temporary until we get rid of photo['profile'] and just use photo['photo_flags'] - // but this will require updating all existing photos in the DB. - - $p['profile'] = (($p['photo_flags'] & PHOTO_PROFILE) ? 1 : 0); - + if(! intval($p['scale'])) + logger('save: ' . print_r($arr,true)); $x = q("select id from photo where resource_id = '%s' and uid = %d and xchan = '%s' and `scale` = %d limit 1", dbesc($p['resource_id']), @@ -338,10 +338,10 @@ abstract class photo_driver { `height` = %d, `width` = %d, `data` = '%s', + `os_storage` = %d, `size` = %d, `scale` = %d, - `profile` = %d, - `photo_flags` = %d, + `photo_usage` = %d, `title` = '%s', `description` = '%s', `allow_cid` = '%s', @@ -361,11 +361,11 @@ abstract class photo_driver { dbesc($p['album']), intval($this->getHeight()), intval($this->getWidth()), - dbescbin($this->imageString()), + (intval($p['os_storage']) ? dbesc($p['os_path']) : dbescbin($this->imageString())), + intval($p['os_storage']), intval(strlen($this->imageString())), intval($p['scale']), - intval($p['profile']), - intval($p['photo_flags']), + intval($p['photo_usage']), dbesc($p['title']), dbesc($p['description']), dbesc($p['allow_cid']), @@ -377,7 +377,7 @@ abstract class photo_driver { } else { $r = q("INSERT INTO `photo` - ( `aid`, `uid`, `xchan`, `resource_id`, `created`, `edited`, `filename`, type, `album`, `height`, `width`, `data`, `size`, `scale`, `profile`, `photo_flags`, `title`, `description`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid` ) + ( `aid`, `uid`, `xchan`, `resource_id`, `created`, `edited`, `filename`, type, `album`, `height`, `width`, `data`, `os_storage`, `size`, `scale`, `photo_usage`, `title`, `description`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid` ) VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s' )", intval($p['aid']), intval($p['uid']), @@ -390,11 +390,11 @@ abstract class photo_driver { dbesc($p['album']), intval($this->getHeight()), intval($this->getWidth()), - dbescbin($this->imageString()), + (intval($p['os_storage']) ? dbesc($p['os_path']) : dbescbin($this->imageString())), + intval($p['os_storage']), intval(strlen($this->imageString())), intval($p['scale']), - intval($p['profile']), - intval($p['photo_flags']), + intval($p['photo_usage']), dbesc($p['title']), dbesc($p['description']), dbesc($p['allow_cid']), @@ -406,7 +406,7 @@ abstract class photo_driver { return $r; } - public function store($aid, $uid, $xchan, $rid, $filename, $album, $scale, $profile = 0, $allow_cid = '', $allow_gid = '', $deny_cid = '', $deny_gid = '') { + public function store($aid, $uid, $xchan, $rid, $filename, $album, $scale, $usage = PHOTO_NORMAL, $allow_cid = '', $allow_gid = '', $deny_cid = '', $deny_gid = '') { $x = q("select id from photo where `resource_id` = '%s' and uid = %d and `xchan` = '%s' and `scale` = %d limit 1", dbesc($rid), @@ -430,7 +430,7 @@ abstract class photo_driver { `data` = '%s', `size` = %d, `scale` = %d, - `profile` = %d, + `photo_usage` = %d, `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', @@ -451,7 +451,7 @@ abstract class photo_driver { dbescbin($this->imageString()), intval(strlen($this->imageString())), intval($scale), - intval($profile), + intval($photo_usage), dbesc($allow_cid), dbesc($allow_gid), dbesc($deny_cid), @@ -461,7 +461,7 @@ abstract class photo_driver { } else { $r = q("INSERT INTO `photo` - ( `aid`, `uid`, `xchan`, `resource_id`, `created`, `edited`, `filename`, type, `album`, `height`, `width`, `data`, `size`, `scale`, `profile`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid` ) + ( `aid`, `uid`, `xchan`, `resource_id`, `created`, `edited`, `filename`, type, `album`, `height`, `width`, `data`, `size`, `scale`, `photo_usage`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid` ) VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, %d, '%s', '%s', '%s', '%s' )", intval($aid), intval($uid), @@ -477,7 +477,7 @@ abstract class photo_driver { dbescbin($this->imageString()), intval(strlen($this->imageString())), intval($scale), - intval($profile), + intval($photo_usage), dbesc($allow_cid), dbesc($allow_gid), dbesc($deny_cid), @@ -557,19 +557,19 @@ function guess_image_type($filename, $headers = '') { } -function import_profile_photo($photo,$xchan,$thing = false) { +function import_xchan_photo($photo,$xchan,$thing = false) { $a = get_app(); $flags = (($thing) ? PHOTO_THING : PHOTO_XCHAN); $album = (($thing) ? 'Things' : 'Contact Photos'); - logger('import_profile_photo: updating channel photo from ' . $photo . ' for ' . $xchan, LOGGER_DEBUG); + logger('import_xchan_photo: updating channel photo from ' . $photo . ' for ' . $xchan, LOGGER_DEBUG); if($thing) $hash = photo_new_resource(); else { - $r = q("select resource_id from photo where xchan = '%s' and (photo_flags & %d )>0 and scale = 4 limit 1", + $r = q("select resource_id from photo where xchan = '%s' and photo_usage = %d and scale = 4 limit 1", dbesc($xchan), intval(PHOTO_XCHAN) ); @@ -591,67 +591,85 @@ function import_profile_photo($photo,$xchan,$thing = false) { if(! $type) $type = 'image/jpeg'; + $result = z_fetch_url($photo,true); - if($result['success']) + if($result['success']) { $img_str = $result['body']; - } - $img = photo_factory($img_str, $type); - if($img->is_valid()) { - $width = $img->getWidth(); - $height = $img->getHeight(); - - if($width && $height) { - if(($width / $height) > 1.2) { - // crop out the sides - $margin = $width - $height; - $img->cropImage(300,($margin / 2),0,$height,$height); - } - elseif(($height / $width) > 1.2) { - // crop out the bottom - $margin = $height - $width; - $img->cropImage(300,0,0,$width,$width); - - } - else { - $img->scaleImageSquare(300); + $h = explode("\n",$result['header']); + if($h) { + foreach($h as $hl) { + if(stristr($hl,'content-type:')) { + if(! stristr($hl,'image/')) { + $photo_failure = true; + } + } + } } - } - else - $photo_failure = true; + } + else { + $photo_failure = true; + } - $p = array('xchan' => $xchan,'resource_id' => $hash, 'filename' => basename($photo), 'album' => $album, 'photo_flags' => $flags, 'scale' => 4); + if(! $photo_failure) { + $img = photo_factory($img_str, $type); + if($img->is_valid()) { + $width = $img->getWidth(); + $height = $img->getHeight(); + + if($width && $height) { + if(($width / $height) > 1.2) { + // crop out the sides + $margin = $width - $height; + $img->cropImage(300,($margin / 2),0,$height,$height); + } + elseif(($height / $width) > 1.2) { + // crop out the bottom + $margin = $height - $width; + $img->cropImage(300,0,0,$width,$width); - $r = $img->save($p); + } + else { + $img->scaleImageSquare(300); + } - if($r === false) - $photo_failure = true; + } + else + $photo_failure = true; - $img->scaleImage(80); - $p['scale'] = 5; + $p = array('xchan' => $xchan,'resource_id' => $hash, 'filename' => basename($photo), 'album' => $album, 'photo_usage' => $flags, 'scale' => 4); - $r = $img->save($p); + $r = $img->save($p); - if($r === false) - $photo_failure = true; + if($r === false) + $photo_failure = true; - $img->scaleImage(48); - $p['scale'] = 6; + $img->scaleImage(80); + $p['scale'] = 5; + + $r = $img->save($p); - $r = $img->save($p); + if($r === false) + $photo_failure = true; + + $img->scaleImage(48); + $p['scale'] = 6; + + $r = $img->save($p); - if($r === false) - $photo_failure = true; + if($r === false) + $photo_failure = true; - $photo = $a->get_baseurl() . '/photo/' . $hash . '-4'; - $thumb = $a->get_baseurl() . '/photo/' . $hash . '-5'; - $micro = $a->get_baseurl() . '/photo/' . $hash . '-6'; - } - else { - logger('import_profile_photo: invalid image from ' . $photo); - $photo_failure = true; + $photo = $a->get_baseurl() . '/photo/' . $hash . '-4'; + $thumb = $a->get_baseurl() . '/photo/' . $hash . '-5'; + $micro = $a->get_baseurl() . '/photo/' . $hash . '-6'; + } + else { + logger('import_xchan_photo: invalid image from ' . $photo); + $photo_failure = true; + } } if($photo_failure) { $photo = $a->get_baseurl() . '/' . get_default_profile_photo(); @@ -684,7 +702,7 @@ function import_channel_photo($photo,$type,$aid,$uid) { $img->scaleImageSquare(300); - $p = array('aid' => $aid, 'uid' => $uid, 'resource_id' => $hash, 'filename' => $filename, 'album' => t('Profile Photos'), 'photo_flags' => PHOTO_PROFILE, 'scale' => 4); + $p = array('aid' => $aid, 'uid' => $uid, 'resource_id' => $hash, 'filename' => $filename, 'album' => t('Profile Photos'), 'photo_usage' => PHOTO_PROFILE, 'scale' => 4); $r = $img->save($p); diff --git a/include/photos.php b/include/photos.php index ca8c53679..49aab6865 100644 --- a/include/photos.php +++ b/include/photos.php @@ -22,40 +22,55 @@ function photo_upload($channel, $observer, $args) { $channel_id = $channel['channel_id']; $account_id = $channel['channel_account_id']; - if(! perm_is_allowed($channel_id, $observer['xchan_hash'], 'post_photos')) { + if(! perm_is_allowed($channel_id, $observer['xchan_hash'], 'write_storage')) { $ret['message'] = t('Permission denied.'); return $ret; } - call_hooks('photo_upload_begin', $args); +// call_hooks('photo_upload_begin', $args); /* * Determine the album to use */ $album = $args['album']; - $newalbum = $args['newalbum']; - - logger('photo_upload: album= ' . $album . ' newalbum= ' . $newalbum , LOGGER_DEBUG); - - if(! $album) { - if($newalbum) - $album = $newalbum; - else - $album = datetime_convert('UTC',date_default_timezone_get(),'now', 'Y-m'); - } if(intval($args['visible']) || $args['visible'] === 'true') $visible = 1; else $visible = 0; - $str_group_allow = perms2str(((is_array($args['group_allow'])) ? $args['group_allow'] : explode(',',$args['group_allow']))); - $str_contact_allow = perms2str(((is_array($args['contact_allow'])) ? $args['contact_allow'] : explode(',',$args['contact_allow']))); - $str_group_deny = perms2str(((is_array($args['group_deny'])) ? $args['group_deny'] : explode(',',$args['group_deny']))); - $str_contact_deny = perms2str(((is_array($args['contact_deny'])) ? $args['contact_deny'] : explode(',',$args['contact_deny']))); + // Set to default channel permissions. If the parent directory (album) has permissions set, + // use those instead. If we have specific permissions supplied, they take precedence over + // all other settings. 'allow_cid' being passed from an external source takes priority over channel settings. + // ...messy... needs re-factoring once the photos/files integration stabilises + + $acl = new AccessList($channel); + if(array_key_exists('directory',$args) && $args['directory']) + $acl->set($args['directory']); + if(array_key_exists('allow_cid',$args)) + $acl->set($args); + if( (array_key_exists('group_allow',$args)) + || (array_key_exists('contact_allow',$args)) + || (array_key_exists('group_deny',$args)) + || (array_key_exists('contact_deny',$args))) { + $acl->set_from_array($args); + } + + $ac = $acl->get(); - if ($args['data']) { + $os_storage = 0; + + if($args['os_path'] && $args['getimagesize']) { + $imagedata = @file_get_contents($args['os_path']); + $filename = $args['filename']; + $filesize = strlen($imagedata); + // this is going to be deleted if it exists + $src = '/tmp/deletemenow'; + $type = $args['getimagesize']['mime']; + $os_storage = 1; + } + elseif ($args['data']) { // allow an import from a binary string representing the image. // This bypasses the upload step and max size limit checking @@ -69,7 +84,7 @@ function photo_upload($channel, $observer, $args) { } else { $f = array('src' => '', 'filename' => '', 'filesize' => 0, 'type' => ''); - call_hooks('photo_upload_file',$f); +// call_hooks('photo_upload_file',$f); if (x($f,'src') && x($f,'filesize')) { $src = $f['src']; @@ -132,7 +147,7 @@ function photo_upload($channel, $observer, $args) { return $ret; } - $exif = $ph->orient($src); + $exif = $ph->orient(($args['os_path']) ? $args['os_path'] : $src); @unlink($src); @@ -156,9 +171,10 @@ function photo_upload($channel, $observer, $args) { $errors = false; $p = array('aid' => $account_id, 'uid' => $channel_id, 'xchan' => $visitor, 'resource_id' => $photo_hash, - 'filename' => $filename, 'album' => $album, 'scale' => 0, 'photo_flags' => PHOTO_NORMAL, - 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_group_allow, - 'deny_cid' => $str_contact_deny, 'deny_gid' => $str_group_deny + 'filename' => $filename, 'album' => $album, 'scale' => 0, 'photo_usage' => PHOTO_NORMAL, + 'allow_cid' => $ac['allow_cid'], 'allow_gid' => $ac['allow_gid'], + 'deny_cid' => $ac['deny_cid'], 'deny_gid' => $ac['deny_gid'], + 'os_storage' => $os_storage, 'os_path' => $args['os_path'] ); if($args['created']) $p['created'] = $args['created']; @@ -173,6 +189,10 @@ function photo_upload($channel, $observer, $args) { if(! $r1) $errors = true; + + unset($p['os_storage']); + unset($p['os_path']); + if(($width > 640 || $height > 640) && (! $errors)) { $ph->scaleImage(640); $p['scale'] = 1; @@ -206,10 +226,10 @@ function photo_upload($channel, $observer, $args) { $width_x_height = $ph->getWidth() . 'x' . $ph->getHeight(); - $mid = item_message_id(); - // Create item container + $item_hidden = (($visible) ? 0 : 1 ); + $lat = $lon = null; if($exif && $exif['GPS']) { @@ -219,62 +239,105 @@ function photo_upload($channel, $observer, $args) { } } - $item_flags = ITEM_WALL|ITEM_ORIGIN|ITEM_THREAD_TOP; - $item_restrict = (($visible) ? ITEM_VISIBLE : ITEM_HIDDEN); - $title = ''; - $mid = item_message_id(); + if($args['item']) { + foreach($args['item'] as $i) { - $arr = array(); + $item = get_item_elements($i); + $force = false; - if($lat && $lon) - $arr['coord'] = $lat . ' ' . $lon; - - $arr['aid'] = $account_id; - $arr['uid'] = $channel_id; - $arr['mid'] = $mid; - $arr['parent_mid'] = $mid; - $arr['item_flags'] = $item_flags; - $arr['item_restrict'] = $item_restrict; - $arr['resource_type'] = 'photo'; - $arr['resource_id'] = $photo_hash; - $arr['owner_xchan'] = $channel['channel_hash']; - $arr['author_xchan'] = $observer['xchan_hash']; - $arr['title'] = $title; - $arr['allow_cid'] = $str_contact_allow; - $arr['allow_gid'] = $str_group_allow; - $arr['deny_cid'] = $str_contact_deny; - $arr['deny_gid'] = $str_group_deny; - $arr['verb'] = ACTIVITY_POST; - - $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid']; - - // We should also put a width_x_height on large photos. Left as an exercise for - // devs looking fo simple stuff to fix. - - $larger = feature_enabled($channel['channel_id'], 'large_photos'); - if($larger) { - $tag = '[zmg]'; - if($r2) - $smallest = 1; - else - $smallest = 0; + if($item['mid'] === $item['parent_mid']) { + + $item['body'] = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo_hash . ']' + . $tag . z_root() . "/photo/{$photo_hash}-{$smallest}.".$ph->getExt() . '[/zmg]' + . '[/zrl]'; + + if($item['author_xchan'] === $channel['channel_hash']) { + $item['sig'] = base64url_encode(rsa_sign($item['body'],$channel['channel_prvkey'])); + $item['item_verified'] = 1; + } + else { + $item['sig'] = ''; + } + $force = true; + + } + $r = q("select id, edited from item where mid = '%s' and uid = %d limit 1", + dbesc($item['mid']), + intval($channel['channel_id']) + ); + if($r) { + if(($item['edited'] > $r[0]['edited']) || $force) { + $item['id'] = $r[0]['id']; + $item['uid'] = $channel['channel_id']; + item_store_update($item); + continue; + } + } + else { + $item['aid'] = $channel['channel_account_id']; + $item['uid'] = $channel['channel_id']; + $item_result = item_store($item); + } + } } else { - if ($width_x_height) - $tag = '[zmg=' . $width_x_height. ']'; - else + $title = ''; + $mid = item_message_id(); + + $arr = array(); + + if($lat && $lon) + $arr['coord'] = $lat . ' ' . $lon; + + $arr['aid'] = $account_id; + $arr['uid'] = $channel_id; + $arr['mid'] = $mid; + $arr['parent_mid'] = $mid; + $arr['item_hidden'] = $item_hidden; + $arr['resource_type'] = 'photo'; + $arr['resource_id'] = $photo_hash; + $arr['owner_xchan'] = $channel['channel_hash']; + $arr['author_xchan'] = $observer['xchan_hash']; + $arr['title'] = $title; + $arr['allow_cid'] = $ac['allow_cid']; + $arr['allow_gid'] = $ac['allow_gid']; + $arr['deny_cid'] = $ac['deny_cid']; + $arr['deny_gid'] = $ac['deny_gid']; + $arr['verb'] = ACTIVITY_POST; + $arr['item_wall'] = 1; + $arr['item_origin'] = 1; + $arr['item_thread_top'] = 1; + $arr['item_private'] = intval($acl->is_private()); + $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid']; + + // We should also put a width_x_height on large photos. Left as an exercise for + // devs looking for simple stuff to fix. + + $larger = feature_enabled($channel['channel_id'], 'large_photos'); + if($larger) { $tag = '[zmg]'; - } + if($r2) + $smallest = 1; + else + $smallest = 0; + } + else { + if ($width_x_height) + $tag = '[zmg=' . $width_x_height. ']'; + else + $tag = '[zmg]'; + } - $arr['body'] = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo_hash . ']' + $arr['body'] = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo_hash . ']' . $tag . z_root() . "/photo/{$photo_hash}-{$smallest}.".$ph->getExt() . '[/zmg]' . '[/zrl]'; - $result = item_store($arr); - $item_id = $result['item_id']; + $result = item_store($arr); + $item_id = $result['item_id']; - if($visible) - proc_run('php', "include/notifier.php", 'wall-new', $item_id); + if($visible) + proc_run('php', "include/notifier.php", 'wall-new', $item_id); + } $ret['success'] = true; $ret['item'] = $arr; @@ -294,7 +357,7 @@ function photo_upload($channel, $observer, $args) { * * @param array $channel * @param array $observer - * @return bool|array false if no view_photos permission or an array + * @return bool|array false if no view_storage permission or an array * * success (bool) * * albums (array) */ @@ -303,14 +366,14 @@ function photos_albums_list($channel, $observer) { $channel_id = $channel['channel_id']; $observer_xchan = (($observer) ? $observer['xchan_hash'] : ''); - if(! perm_is_allowed($channel_id, $observer_xchan, 'view_photos')) + if(! perm_is_allowed($channel_id, $observer_xchan, 'view_storage')) return false; /** @FIXME create a permissions SQL which works on arbitrary observers and channels, regardless of login or web status */ $sql_extra = permissions_sql($channel_id); - $albums = q("SELECT count( distinct resource_id ) as total, album from photo where uid = %d and ( photo_flags = %d or photo_flags = %d ) $sql_extra group by album order by max(created) desc", + $albums = q("SELECT count( distinct resource_id ) as total, album from photo where uid = %d and photo_usage IN ( %d, %d ) $sql_extra group by album order by max(created) desc", intval($channel_id), intval(PHOTO_NORMAL), intval(PHOTO_PROFILE) @@ -325,7 +388,7 @@ function photos_albums_list($channel, $observer) { $ret['albums'] = array(); foreach($albums as $k => $album) { $entry = array( - 'text' => $album['album'], + 'text' => (($album['album']) ? $album['album'] : '/'), 'total' => $album['total'], 'url' => z_root() . '/photos/' . $channel['channel_address'] . '/album/' . bin2hex($album['album']), 'urlencode' => urlencode($album['album']), @@ -359,7 +422,7 @@ function photos_album_widget($channelx,$observer,$albums = null) { '$title' => t('Photo Albums'), '$albums' => $albums['albums'], '$baseurl' => z_root(), - '$upload' => ((perm_is_allowed($channelx['channel_id'],(($observer) ? $observer['xchan_hash'] : ''),'post_photos')) + '$upload' => ((perm_is_allowed($channelx['channel_id'],(($observer) ? $observer['xchan_hash'] : ''),'write_storage')) ? t('Upload New Photos') : '') )); } @@ -380,7 +443,7 @@ function photos_list_photos($channel, $observer, $album = '') { $channel_id = $channel['channel_id']; $observer_xchan = (($observer) ? $observer['xchan_hash'] : ''); - if(! perm_is_allowed($channel_id,$observer_xchan,'view_photos')) + if(! perm_is_allowed($channel_id,$observer_xchan,'view_storage')) return false; $sql_extra = permissions_sql($channel_id); @@ -390,7 +453,7 @@ function photos_list_photos($channel, $observer, $album = '') { $ret = array('success' => false); - $r = q("select resource_id, created, edited, title, description, album, filename, type, height, width, size, scale, profile, photo_flags, allow_cid, allow_gid, deny_cid, deny_gid from photo where uid = %d and ( photo_flags = %d or photo_flags = %d ) $sql_extra ", + $r = q("select resource_id, created, edited, title, description, album, filename, type, height, width, size, scale, photo_usage, allow_cid, allow_gid, deny_cid, deny_gid from photo where uid = %d and photo_usage in ( %d, %d ) $sql_extra ", intval($channel_id), intval(PHOTO_NORMAL), intval(PHOTO_PROFILE) @@ -488,32 +551,34 @@ function photos_create_item($channel, $creator_hash, $photo, $visible = false) { // Create item container - $item_flags = ITEM_WALL|ITEM_ORIGIN|ITEM_THREAD_TOP; - $item_restrict = (($visible) ? ITEM_VISIBLE : ITEM_HIDDEN); + + $item_hidden = (($visible) ? 0 : 1 ); $mid = item_message_id(); $arr = array(); - $arr['aid'] = $channel['channel_account_id']; - $arr['uid'] = $channel['channel_id']; - $arr['mid'] = $mid; - $arr['parent_mid'] = $mid; - $arr['item_flags'] = $item_flags; - $arr['item_restrict'] = $item_restrict; - $arr['resource_type'] = 'photo'; - $arr['resource_id'] = $photo['resource_id']; - $arr['owner_xchan'] = $channel['channel_hash']; - $arr['author_xchan'] = $creator_hash; - - $arr['allow_cid'] = $photo['allow_cid']; - $arr['allow_gid'] = $photo['allow_gid']; - $arr['deny_cid'] = $photo['deny_cid']; - $arr['deny_gid'] = $photo['deny_gid']; - - $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid']; - - $arr['body'] = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo['resource_id'] . ']' + $arr['aid'] = $channel['channel_account_id']; + $arr['uid'] = $channel['channel_id']; + $arr['mid'] = $mid; + $arr['parent_mid'] = $mid; + $arr['item_wall'] = 1; + $arr['item_origin'] = 1; + $arr['item_thread_top'] = 1; + $arr['item_hidden'] = $item_hidden; + $arr['resource_type'] = 'photo'; + $arr['resource_id'] = $photo['resource_id']; + $arr['owner_xchan'] = $channel['channel_hash']; + $arr['author_xchan'] = $creator_hash; + + $arr['allow_cid'] = $photo['allow_cid']; + $arr['allow_gid'] = $photo['allow_gid']; + $arr['deny_cid'] = $photo['deny_cid']; + $arr['deny_gid'] = $photo['deny_gid']; + + $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid']; + + $arr['body'] = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo['resource_id'] . ']' . '[zmg]' . z_root() . '/photo/' . $photo['resource_id'] . '-' . $photo['scale'] . '[/zmg]' . '[/zrl]'; @@ -535,6 +600,16 @@ function getGps($exifCoord, $hemi) { return floatval($flip * ($degrees + ($minutes / 60) + ($seconds / 3600))); } +function getGpstimestamp($exifCoord) { + + $hours = count($exifCoord) > 0 ? gps2Num($exifCoord[0]) : 0; + $minutes = count($exifCoord) > 1 ? gps2Num($exifCoord[1]) : 0; + $seconds = count($exifCoord) > 2 ? gps2Num($exifCoord[2]) : 0; + + return sprintf('%02d:%02d:%02d',$hours,$minutes,$seconds); +} + + function gps2Num($coordPart) { $parts = explode('/', $coordPart); diff --git a/include/poller.php b/include/poller.php index bc48c3f00..031fb4533 100644 --- a/include/poller.php +++ b/include/poller.php @@ -59,10 +59,9 @@ function poller_run($argv, $argc){ // expire any expired items $r = q("select id from item where expires != '%s' and expires < %s - and ( item_restrict & %d ) = 0 ", + and item_deleted = 0 ", dbesc(NULL_DATE), - db_utcnow(), - intval(ITEM_DELETED) + db_utcnow() ); if($r) { require_once('include/items.php'); @@ -91,15 +90,13 @@ function poller_run($argv, $argc){ // (time travel posts). Restrict to items that have come of age in the last // couple of days to limit the query to something reasonable. - $r = q("select id from item where ( item_restrict & %d ) > 0 and created <= %s and created > '%s' ", - intval(ITEM_DELAYED_PUBLISH), + $r = q("select id from item where item_delayed = 1 and created <= %s and created > '%s' ", db_utcnow(), dbesc(datetime_convert('UTC','UTC','now - 2 days')) ); if($r) { foreach($r as $rr) { - $x = q("update item set item_restrict = ( item_restrict & ~%d ) where id = %d", - intval(ITEM_DELAYED_PUBLISH), + $x = q("update item set item_delayed = 0 where id = %d", intval($rr['id']) ); if($x) { @@ -178,6 +175,12 @@ function poller_run($argv, $argc){ logger('regdir: ' . print_r(z_fetch_url(get_directory_primary() . '/regdir?f=&url=' . urlencode(z_root()) . '&realm=' . urlencode(get_directory_realm())),true)); } + // Check for dead sites + proc_run('php', 'include/checksites.php'); + + // update searchable doc indexes + proc_run('php', 'include/importdoc.php'); + /** * End Cron Weekly */ @@ -198,6 +201,17 @@ function poller_run($argv, $argc){ db_utcnow(), db_quoteinterval('30 DAY') ); + // expire old delivery reports + + $keep_reports = intval(get_config('system','expire_delivery_reports')); + if($keep_reports === 0) + $keep_reports = 30; + + q("delete from dreport where dreport_time < %s - INTERVAL %s", + db_utcnow(), + db_quoteinterval($keep_reports . ' DAY') + ); + // expire any expired accounts downgrade_accounts(); @@ -235,7 +249,7 @@ function poller_run($argv, $argc){ if($r) { require_once('include/photo/photo_driver.php'); foreach($r as $rr) { - $photos = import_profile_photo($rr['xchan_photo_l'],$rr['xchan_hash']); + $photos = import_xchan_photo($rr['xchan_photo_l'],$rr['xchan_hash']); $x = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", dbesc($photos[0]), @@ -296,13 +310,11 @@ function poller_run($argv, $argc){ $randfunc = db_getfunc('RAND'); - $contacts = q("SELECT abook_id, abook_flags, abook_updated, abook_connected, abook_closeness, abook_xchan, abook_channel, xchan_network - FROM abook LEFT JOIN xchan on abook_xchan = xchan_hash LEFT JOIN account on abook_account = account_id + $contacts = q("SELECT * FROM abook LEFT JOIN xchan on abook_xchan = xchan_hash + LEFT JOIN account on abook_account = account_id + where abook_self = 0 $sql_extra - AND (( abook_flags & %d ) > 0 OR ( abook_flags = %d )) AND (( account_flags = %d ) OR ( account_flags = %d )) $abandon_sql ORDER BY $randfunc", - intval(ABOOK_FLAG_HIDDEN|ABOOK_FLAG_PENDING|ABOOK_FLAG_UNCONNECTED|ABOOK_FLAG_FEED), - intval(0), intval(ACCOUNT_OK), intval(ACCOUNT_UNVERIFIED) // FIXME @@ -312,15 +324,12 @@ function poller_run($argv, $argc){ foreach($contacts as $contact) { - if($contact['abook_flags'] & ABOOK_FLAG_SELF) - continue; - $update = false; $t = $contact['abook_updated']; $c = $contact['abook_connected']; - if($contact['abook_flags'] & ABOOK_FLAG_FEED) { + if(intval($contact['abook_feed'])) { $min = service_class_fetch($contact['abook_channel'],'minimum_feedcheck_minutes'); if(! $min) $min = intval(get_config('system','minimum_feedcheck_minutes')); @@ -359,15 +368,14 @@ function poller_run($argv, $argc){ // He's dead, Jim if(strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $c . " + 30 day")) > 0) { - $r = q("update abook set abook_flags = (abook_flags | %d) where abook_id = %d", - intval(ABOOK_FLAG_ARCHIVED), + $r = q("update abook set abook_archived = 1 where abook_id = %d", intval($contact['abook_id']) ); $update = false; continue; } - if($contact['abook_flags'] & ABOOK_FLAG_ARCHIVED) { + if(intval($contact['abook_archived'])) { $update = false; continue; } @@ -388,7 +396,7 @@ function poller_run($argv, $argc){ } - if($contact['abook_flags'] & (ABOOK_FLAG_PENDING|ABOOK_FLAG_ARCHIVED|ABOOK_FLAG_IGNORED)) + if(intval($contact['abook_pending']) || intval($contact['abook_archived']) || intval($contact['abook_ignored']) || intval($contact['abook_blocked'])) continue; if((! $update) && (! $force)) diff --git a/include/queue.php b/include/queue.php index 7d2ad3b2d..71ac50c83 100644 --- a/include/queue.php +++ b/include/queue.php @@ -22,6 +22,25 @@ function queue_run($argv, $argc){ logger('queue: start'); + + // delete all queue items more than 3 days old + // but first mark these sites dead if we haven't heard from them in a month + + $r = q("select outq_posturl from outq where outq_created < %s - INTERVAL %s", + db_utcnow(), db_quoteinterval('3 DAY') + ); + if($r) { + foreach($r as $rr) { + $site_url = ''; + $h = parse_url($rr['outq_posturl']); + $desturl = $h['scheme'] . '://' . $h['host'] . (($h['port']) ? ':' . $h['port'] : ''); + q("update site set site_dead = 1 where site_dead = 0 and site_url = '%s' and site_update < %s - INTERVAL %s", + dbesc($desturl), + db_utcnow(), db_quoteinterval('1 MONTH') + ); + } + } + $r = q("DELETE FROM outq WHERE outq_created < %s - INTERVAL %s", db_utcnow(), db_quoteinterval('3 DAY') ); @@ -69,15 +88,34 @@ function queue_run($argv, $argc){ return; foreach($r as $rr) { + + $dresult = null; + if(in_array($rr['outq_posturl'],$deadguys)) continue; + $base = ''; + $h = parse_url($rr['outq_posturl']); + if($h) + $base = $h['scheme'] . '://' . $h['host'] . (($h['port']) ? ':' . $h['port'] : ''); + if($rr['outq_driver'] === 'post') { $result = z_post_url($rr['outq_posturl'],$rr['outq_msg']); if($result['success'] && $result['return_code'] < 300) { logger('queue: queue post success to ' . $rr['outq_posturl'], LOGGER_DEBUG); + if($base) { + q("update site set site_update = '%s', site_dead = 0 where site_url = '%s' ", + dbesc(datetime_convert()), + dbesc($base) + ); + } + q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s' limit 1", + dbesc('accepted for delivery'), + dbesc(datetime_convert()), + dbesc($rr['outq_hash']) + ); $y = q("delete from outq where outq_hash = '%s'", - dbesc($rr['ouq_hash']) + dbesc($rr['outq_hash']) ); } else { @@ -86,6 +124,7 @@ function queue_run($argv, $argc){ dbesc(datetime_convert()), dbesc($rr['outq_hash']) ); + $deadguys[] = $rr['outq_posturl']; } continue; } diff --git a/include/reddav.php b/include/reddav.php index 750ca1b24..c592597a9 100644 --- a/include/reddav.php +++ b/include/reddav.php @@ -1,7 +1,7 @@ <?php /** * @file include/reddav.php - * @brief some DAV related functions for RedMatrix. + * @brief some DAV related functions for Hubzilla. * * This file contains some functions which did not fit into one of the RedDAV * classes. @@ -42,8 +42,7 @@ require_once('include/RedDAV/RedBasicAuth.php'); function RedChannelList(&$auth) { $ret = array(); - $r = q("SELECT channel_id, channel_address FROM channel WHERE NOT (channel_pageflags & %d)>0 AND NOT (channel_pageflags & %d)>0", - intval(PAGE_REMOVED), + $r = q("SELECT channel_id, channel_address FROM channel WHERE channel_removed = 0 AND channel_system = 0 AND NOT (channel_pageflags & %d)>0", intval(PAGE_HIDDEN) ); @@ -115,20 +114,18 @@ function RedCollectionData($file, &$auth) { $permission_error = false; for ($x = 1; $x < count($path_arr); $x++) { - $r = q("SELECT id, hash, filename, flags FROM attach WHERE folder = '%s' AND filename = '%s' AND uid = %d AND (flags & %d)>0 $perms LIMIT 1", + $r = q("SELECT id, hash, filename, flags, is_dir FROM attach WHERE folder = '%s' AND filename = '%s' AND uid = %d AND is_dir != 0 $perms LIMIT 1", dbesc($folder), dbesc($path_arr[$x]), - intval($channel_id), - intval(ATTACH_FLAG_DIR) + intval($channel_id) ); if (! $r) { // path wasn't found. Try without permissions to see if it was the result of permissions. $errors = true; - $r = q("select id, hash, filename, flags from attach where folder = '%s' and filename = '%s' and uid = %d and (flags & %d)>0 limit 1", + $r = q("select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0 limit 1", dbesc($folder), basename($path_arr[$x]), - intval($channel_id), - intval(ATTACH_FLAG_DIR) + intval($channel_id) ); if ($r) { $permission_error = true; @@ -136,7 +133,7 @@ function RedCollectionData($file, &$auth) { break; } - if ($r && ($r[0]['flags'] & ATTACH_FLAG_DIR)) { + if ($r && intval($r[0]['is_dir'])) { $folder = $r[0]['hash']; $path = $path . '/' . $r[0]['filename']; } @@ -162,18 +159,17 @@ function RedCollectionData($file, &$auth) { $prefix = ''; $suffix = 'GROUP BY filename'; } - $r = q("select $prefix id, uid, hash, filename, filetype, filesize, revision, folder, flags, created, edited from attach where folder = '%s' and uid = %d $perms $suffix", + $r = q("select $prefix id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, created, edited from attach where folder = '%s' and uid = %d $perms $suffix", dbesc($folder), intval($channel_id) ); foreach ($r as $rr) { //logger('filename: ' . $rr['filename'], LOGGER_DEBUG); - if ($rr['flags'] & ATTACH_FLAG_DIR) { - // @todo can't we drop '/cloud'? it gets stripped off anyway in RedDirectory - $ret[] = new RedDAV\RedDirectory('/cloud' . $path . '/' . $rr['filename'], $auth); + if (intval($rr['is_dir'])) { + $ret[] = new RedDAV\RedDirectory($path . '/' . $rr['filename'], $auth); } else { - $ret[] = new RedDAV\RedFile('/cloud' . $path . '/' . $rr['filename'], $rr, $auth); + $ret[] = new RedDAV\RedFile($path . '/' . $rr['filename'], $rr, $auth); } } @@ -200,6 +196,12 @@ function RedFileData($file, &$auth, $test = false) { if ($x === 0) { $file = substr($file, 6); } + else { + $x = strpos($file,'/dav'); + if($x === 0) + $file = substr($file,4); + } + if ((! $file) || ($file === '/')) { return new RedDAV\RedDirectory('/', $auth); @@ -237,19 +239,18 @@ function RedFileData($file, &$auth, $test = false) { $errors = false; for ($x = 1; $x < count($path_arr); $x++) { - $r = q("select id, hash, filename, flags from attach where folder = '%s' and filename = '%s' and uid = %d and (flags & %d)>0 $perms", + $r = q("select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0 $perms", dbesc($folder), dbesc($path_arr[$x]), - intval($channel_id), - intval(ATTACH_FLAG_DIR) + intval($channel_id) ); - if ($r && ( $r[0]['flags'] & ATTACH_FLAG_DIR)) { + if ($r && intval($r[0]['is_dir'])) { $folder = $r[0]['hash']; $path = $path . '/' . $r[0]['filename']; } if (! $r) { - $r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, created, edited from attach + $r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach where folder = '%s' and filename = '%s' and uid = %d $perms order by filename limit 1", dbesc($folder), dbesc(basename($file)), @@ -258,7 +259,7 @@ function RedFileData($file, &$auth, $test = false) { } if (! $r) { $errors = true; - $r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, created, edited from attach + $r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach where folder = '%s' and filename = '%s' and uid = %d order by filename limit 1", dbesc($folder), dbesc(basename($file)), @@ -273,7 +274,7 @@ function RedFileData($file, &$auth, $test = false) { if ($test) return true; // final component was a directory. - return new RedDAV\RedDirectory('/cloud/' . $file, $auth); + return new RedDAV\RedDirectory($file, $auth); } if ($errors) { @@ -291,11 +292,10 @@ function RedFileData($file, &$auth, $test = false) { if ($test) return true; - if ($r[0]['flags'] & ATTACH_FLAG_DIR) { - // @todo can't we drop '/cloud'? it gets stripped off anyway in RedDirectory - return new RedDAV\RedDirectory('/cloud' . $path . '/' . $r[0]['filename'], $auth); + if (intval($r[0]['is_dir'])) { + return new RedDAV\RedDirectory($path . '/' . $r[0]['filename'], $auth); } else { - return new RedDAV\RedFile('/cloud' . $path . '/' . $r[0]['filename'], $r[0], $auth); + return new RedDAV\RedFile($path . '/' . $r[0]['filename'], $r[0], $auth); } } return false; diff --git a/include/security.php b/include/security.php index 0c3dc29d6..9a25d9e0e 100644 --- a/include/security.php +++ b/include/security.php @@ -71,9 +71,8 @@ function authenticate_success($user_record, $login_initial = false, $interactive /* This account has never created a channel. Send them to new_channel by default */ if($a->module === 'login') { - $r = q("select count(channel_id) as total from channel where channel_account_id = %d and not ( channel_pageflags & %d)>0", - intval($a->account['account_id']), - intval(PAGE_REMOVED) + $r = q("select count(channel_id) as total from channel where channel_account_id = %d and channel_removed = 0 ", + intval($a->account['account_id']) ); if(($r) && (! $r[0]['total'])) goaway(z_root() . '/new_channel'); @@ -94,20 +93,17 @@ function change_channel($change_channel) { $ret = false; if($change_channel) { - $r = q("select channel.*, xchan.* from channel left join xchan on channel.channel_hash = xchan.xchan_hash where channel_id = %d and channel_account_id = %d and not ( channel_pageflags & %d)>0 limit 1", + $r = q("select channel.*, xchan.* from channel left join xchan on channel.channel_hash = xchan.xchan_hash where channel_id = %d and channel_account_id = %d and channel_removed = 0 limit 1", intval($change_channel), - intval(get_account_id()), - intval(PAGE_REMOVED) + intval(get_account_id()) ); // It's not there. Is this an administrator, and is this the sys channel? if (is_developer()) { if (! $r) { if (is_site_admin()) { - $r = q("select channel.*, xchan.* from channel left join xchan on channel.channel_hash = xchan.xchan_hash where channel_id = %d and ( channel_pageflags & %d) and not (channel_pageflags & %d )>0 limit 1", - intval($change_channel), - intval(PAGE_SYSTEM), - intval(PAGE_REMOVED) + $r = q("select channel.*, xchan.* from channel left join xchan on channel.channel_hash = xchan.xchan_hash where channel_id = %d and channel_system = 1 and channel_removed = 0 limit 1", + intval($change_channel) ); } } @@ -249,6 +245,9 @@ function item_permissions_sql($owner_id, $remote_observer = null) { $observer = (($remote_observer) ? $remote_observer : get_observer_hash()); if($observer) { + + $s = scopes_sql($owner_id,$observer); + $groups = init_groups_visitor($observer); $gs = '<<>>'; // should be impossible to match @@ -259,9 +258,9 @@ function item_permissions_sql($owner_id, $remote_observer = null) { } $regexop = db_getfunc('REGEXP'); $sql = sprintf( - " AND ( NOT (deny_cid like '%s' OR deny_gid $regexop '%s') - AND ( allow_cid like '%s' OR allow_gid $regexop '%s' OR ( allow_cid = '' AND allow_gid = '' AND item_private = 0 ) ) - ) + " AND (( NOT (deny_cid like '%s' OR deny_gid $regexop '%s') + AND ( allow_cid like '%s' OR allow_gid $regexop '%s' OR ( allow_cid = '' AND allow_gid = '' AND item_private = 0 )) + ) OR ( item_private = 1 $s )) ", dbesc(protect_sprintf( '%<' . $observer . '>%')), dbesc($gs), @@ -275,6 +274,39 @@ function item_permissions_sql($owner_id, $remote_observer = null) { } /** + * Remote visitors also need to be checked against the public_scope parameter if item_private is set. + * This function checks the various permutations of that field for any which apply to this observer. + * + */ + + + +function scopes_sql($uid,$observer) { + $str = " and ( public_policy = 'authenticated' "; + if(! is_foreigner($observer)) + $str .= " or public_policy = 'network: red' "; + if(local_channel()) + $str .= " or public_policy = 'site: " . get_app()->get_hostname() . "' "; + + $ab = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", + dbesc($observer), + intval($uid) + ); + if(! $ab) + return $str . " ) "; + if($ab[0]['abook_pending']) + $str .= " or public_policy = 'any connections' "; + $str .= " or public_policy = 'contacts' ) "; + return $str; +} + + + + + + + +/** * @param string $observer_hash * * @return string additional SQL where statement @@ -404,9 +436,9 @@ function stream_perms_api_uids($perms = NULL, $limit = 0, $rand = 0 ) { $random_sql = (($rand) ? " ORDER BY " . db_getfunc('RAND') . " " : ''); if(local_channel()) $ret[] = local_channel(); - $r = q("select channel_id from channel where channel_r_stream > 0 and ( channel_r_stream & %d )>0 and ( channel_pageflags & %d ) = 0 $random_sql $limit_sql ", + $r = q("select channel_id from channel where channel_r_stream > 0 and ( channel_r_stream & %d )>0 and ( channel_pageflags & %d ) = 0 and channel_system = 0 and channel_removed = 0 $random_sql $limit_sql ", intval($perms), - intval(PAGE_ADULT|PAGE_CENSORED|PAGE_SYSTEM|PAGE_REMOVED) + intval(PAGE_ADULT|PAGE_CENSORED) ); if($r) { foreach($r as $rr) @@ -437,9 +469,9 @@ function stream_perms_xchans($perms = NULL ) { if(local_channel()) $ret[] = get_observer_hash(); - $r = q("select channel_hash from channel where channel_r_stream > 0 and (channel_r_stream & %d)>0 and not (channel_pageflags & %d)>0", + $r = q("select channel_hash from channel where channel_r_stream > 0 and (channel_r_stream & %d)>0 and not (channel_pageflags & %d)>0 and channel_system = 0 and channel_removed = 0 ", intval($perms), - intval(PAGE_ADULT|PAGE_CENSORED|PAGE_SYSTEM|PAGE_REMOVED) + intval(PAGE_ADULT|PAGE_CENSORED) ); if($r) { foreach($r as $rr) diff --git a/include/session.php b/include/session.php index 31b3f0614..92004bc18 100644 --- a/include/session.php +++ b/include/session.php @@ -98,9 +98,6 @@ function ref_session_destroy ($id) { function ref_session_gc($expire) { q("DELETE FROM session WHERE expire < %d", dbesc(time())); - if (! get_config('system', 'innodb')) - db_optimizetable('session'); - return true; } diff --git a/include/socgraph.php b/include/socgraph.php index 0ad7c4034..e44a8ea9a 100644 --- a/include/socgraph.php +++ b/include/socgraph.php @@ -40,7 +40,7 @@ function poco_load($xchan = '', $url = null) { return; } - $url = $url . '?f=&fields=displayName,hash,urls,photos,rating' ; + $url = $url . '?f=&fields=displayName,hash,urls,photos' ; logger('poco_load: ' . $url, LOGGER_DEBUG); @@ -115,8 +115,6 @@ function poco_load($xchan = '', $url = null) { $name = $entry['displayName']; $hash = $entry['hash']; - $rating = ((array_key_exists('rating',$entry) && (! is_array($entry['rating']))) ? intval($entry['rating']) : 0); - $rating_text = ((array_key_exists('rating_text',$entry)) ? escape_tags($entry['rating_text']) :''); if(x($entry,'urls') && is_array($entry['urls'])) { foreach($entry['urls'] as $url) { @@ -214,7 +212,7 @@ function poco_load($xchan = '', $url = null) { function count_common_friends($uid,$xchan) { $r = q("SELECT count(xlink_id) as total from xlink where xlink_xchan = '%s' and xlink_static = 0 and xlink_link in - (select abook_xchan from abook where abook_xchan != '%s' and abook_channel = %d and abook_flags = 0 )", + (select abook_xchan from abook where abook_xchan != '%s' and abook_channel = %d and abook_self = 0 )", dbesc($xchan), dbesc($xchan), intval($uid) @@ -235,7 +233,7 @@ function common_friends($uid,$xchan,$start = 0,$limit=100000000,$shuffle = false $sql_extra = " order by xchan_name asc "; $r = q("SELECT * from xchan left join xlink on xlink_link = xchan_hash where xlink_xchan = '%s' and xlink_static = 0 and xlink_link in - (select abook_xchan from abook where abook_xchan != '%s' and abook_channel = %d and abook_flags = 0 ) $sql_extra limit %d offset %d", + (select abook_xchan from abook where abook_xchan != '%s' and abook_channel = %d and abook_self = 0 ) $sql_extra limit %d offset %d", dbesc($xchan), dbesc($xchan), intval($uid), @@ -329,15 +327,13 @@ function suggestion_query($uid, $myxchan, $start = 0, $limit = 80) { and not xlink_link in ( select abook_xchan from abook where abook_channel = %d ) and not xlink_link in ( select xchan from xign where uid = %d ) and xlink_xchan != '' + and xchan_hidden = 0 + and xchan_deleted = 0 and xlink_static = 0 - and not ( xchan_flags & %d )>0 - and not ( xchan_flags & %d )>0 group by xchan_hash order by total desc limit %d offset %d ", intval($uid), intval($uid), intval($uid), - intval(XCHAN_FLAGS_HIDDEN), - intval(XCHAN_FLAGS_DELETED), intval($limit), intval($start) ); @@ -350,14 +346,12 @@ function suggestion_query($uid, $myxchan, $start = 0, $limit = 80) { where xlink_xchan = '' and not xlink_link in ( select abook_xchan from abook where abook_channel = %d ) and not xlink_link in ( select xchan from xign where uid = %d ) + and xchan_hidden = 0 + and xchan_deleted = 0 and xlink_static = 0 - and not ( xchan_flags & %d )>0 - and not ( xchan_flags & %d )>0 group by xchan_hash order by total desc limit %d offset %d ", intval($uid), intval($uid), - intval(XCHAN_FLAGS_HIDDEN), - intval(XCHAN_FLAGS_DELETED), intval($limit), intval($start) ); @@ -465,16 +459,16 @@ function poco($a,$extended = false) { } if($justme) - $sql_extra = " and ( abook_flags & " . ABOOK_FLAG_SELF . " )>0 "; + $sql_extra = " and abook_self = 1 "; else - $sql_extra = " and abook_flags = 0 "; + $sql_extra = " and abook_self = 0 "; if($cid) - $sql_extra = sprintf(" and abook_id = %d and ( abook_flags & " . ABOOK_FLAG_HIDDEN . " ) = 0 ",intval($cid)); + $sql_extra = sprintf(" and abook_id = %d and abook_hidden = 0 ",intval($cid)); if($system_mode) { - $r = q("SELECT count(*) as `total` from abook where ( abook_flags & " . ABOOK_FLAG_SELF . - " )>0 and abook_channel in (select uid from pconfig where cat = 'system' and k = 'suggestme' and v = '1') "); + $r = q("SELECT count(*) as `total` from abook where abook_self = 1 + and abook_channel in (select uid from pconfig where cat = 'system' and k = 'suggestme' and v = '1') "); } else { $r = q("SELECT count(*) as `total` from abook where abook_channel = %d @@ -497,8 +491,9 @@ function poco($a,$extended = false) { $itemsPerPage = ((x($_GET,'count') && intval($_GET['count'])) ? intval($_GET['count']) : $totalResults); if($system_mode) { - $r = q("SELECT abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash where ( abook_flags & " . ABOOK_FLAG_SELF . - " )>0 and abook_channel in (select uid from pconfig where cat = 'system' and k = 'suggestme' and v = '1') limit %d offset %d ", + $r = q("SELECT abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash where abook_self = 1 + and abook_channel in (select uid from pconfig where cat = 'system' and k = 'suggestme' and v = '1') + limit %d offset %d ", intval($itemsPerPage), intval($startIndex) ); @@ -580,13 +575,6 @@ function poco($a,$extended = false) { $entry['preferredUsername'] = substr($rr['xchan_addr'],0,strpos($rr['xchan_addr'],'@')); if($fields_ret['photos']) $entry['photos'] = array(array('value' => $rr['xchan_photo_l'], 'mimetype' => $rr['xchan_photo_mimetype'], 'type' => 'profile')); - if($fields_ret['rating']) { - $entry['rating'] = ((array_key_exists('abook_rating',$rr)) ? intval($rr['abook_rating']) : 0); - $entry['rating_text'] = ((array_key_exists('abook_rating_text',$rr)) ? $rr['abook_rating_text'] : ''); - // maybe this should be a composite calculated rating in $system_mode - if($system_mode) - $entry['rating'] = 0; - } $ret['entry'][] = $entry; } } @@ -609,4 +597,4 @@ function poco($a,$extended = false) { else http_status_exit(500); -}
\ No newline at end of file +} diff --git a/include/statistics_fns.php b/include/statistics_fns.php index 288925a2c..ce2eee5e7 100644 --- a/include/statistics_fns.php +++ b/include/statistics_fns.php @@ -23,8 +23,7 @@ function update_channels_active_halfyear_stat() { $s .= ','; $s .= intval($rr['channel_id']); } - $x = q("select uid from item where uid in ( $s ) and (item_flags & %d)>0 and created > %s - INTERVAL %s group by uid", - intval(ITEM_WALL), + $x = q("select uid from item where uid in ( $s ) and item_wall = 1 and created > %s - INTERVAL %s group by uid", db_utcnow(), db_quoteinterval('6 MONTH') ); if($x) { @@ -50,8 +49,7 @@ function update_channels_active_monthly_stat() { $s .= ','; $s .= intval($rr['channel_id']); } - $x = q("select uid from item where uid in ( $s ) and ( item_flags & %d )>0 and created > %s - INTERVAL %s group by uid", - intval(ITEM_WALL), + $x = q("select uid from item where uid in ( $s ) and item_wall = 1 and created > %s - INTERVAL %s group by uid", db_utcnow(), db_quoteinterval('1 MONTH') ); if($x) { @@ -66,8 +64,7 @@ function update_channels_active_monthly_stat() { } function update_local_posts_stat() { - $posts = q("SELECT COUNT(*) AS local_posts FROM `item` WHERE (item_flags & %d)>0 ", - intval(ITEM_WALL) ); + $posts = q("SELECT COUNT(*) AS local_posts FROM `item` WHERE item_wall = 1 "); if (is_array($posts)) { $local_posts_stat = intval($posts[0]["local_posts"]); set_config('system','local_posts_stat',$local_posts_stat); diff --git a/include/taxonomy.php b/include/taxonomy.php index a5da190d4..a82cf94f7 100644 --- a/include/taxonomy.php +++ b/include/taxonomy.php @@ -101,7 +101,7 @@ 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, $restrict = 0, $type = TERM_HASHTAG) { +function tagadelic($uid, $count = 0, $authors = '', $owner = '', $flags = 0, $restrict = 0, $type = TERM_HASHTAG) { require_once('include/security.php'); @@ -111,8 +111,10 @@ function tagadelic($uid, $count = 0, $authors = '', $flags = 0, $restrict = 0, $ $sql_options = item_permissions_sql($uid); $count = intval($count); - if($flags) - $sql_options .= " and ((item_flags & " . intval($flags) . ") = " . intval($flags) . ") "; + if($flags) { + if($flags === 'wall') + $sql_options .= " and item_wall = 1 "; + } if($authors) { if(! is_array($authors)) @@ -122,10 +124,15 @@ function tagadelic($uid, $count = 0, $authors = '', $flags = 0, $restrict = 0, $ $sql_options .= " and author_xchan in (" . implode(',',$authors) . ") "; } + if($owner) { + $sql_options .= " and owner_xchan = '" . dbesc($owner) . "' "; + } + + // 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 = %d + and otype = %d and item_type = %d and item_private = 0 $sql_options group by term order by total desc %s", intval($uid), @@ -213,10 +220,10 @@ function dir_tagadelic($count = 0) { } -function tagblock($link,$uid,$count = 0,$authors = '',$flags = 0,$restrict = 0,$type = TERM_HASHTAG) { +function tagblock($link,$uid,$count = 0,$authors = '',$owner = '', $flags = 0,$restrict = 0,$type = TERM_HASHTAG) { $o = ''; - $r = tagadelic($uid,$count,$authors,$flags,$restrict,$type); + $r = tagadelic($uid,$count,$authors,$owner, $flags,$restrict,$type); if($r) { $o = '<div class="tagblock widget"><h3>' . t('Tags') . '</h3><div class="tags" align="center">'; @@ -230,10 +237,10 @@ function tagblock($link,$uid,$count = 0,$authors = '',$flags = 0,$restrict = 0,$ } -function wtagblock($uid,$count = 0,$authors = '',$flags = 0,$restrict = 0,$type = TERM_HASHTAG) { +function wtagblock($uid,$count = 0,$authors = '',$owner = '', $flags = 0,$restrict = 0,$type = TERM_HASHTAG) { $o = ''; - $r = tagadelic($uid,$count,$authors,$flags,$restrict,$type); + $r = tagadelic($uid,$count,$authors,$owner, $flags,$restrict,$type); if($r) { $c = q("select channel_address from channel where channel_id = %d limit 1", @@ -251,10 +258,10 @@ function wtagblock($uid,$count = 0,$authors = '',$flags = 0,$restrict = 0,$type } -function catblock($uid,$count = 0,$authors = '',$flags = 0,$restrict = 0,$type = TERM_CATEGORY) { +function catblock($uid,$count = 0,$authors = '',$owner = '', $flags = 0,$restrict = 0,$type = TERM_CATEGORY) { $o = ''; - $r = tagadelic($uid,$count,$authors,$flags,$restrict,$type); + $r = tagadelic($uid,$count,$authors,$owner,$flags,$restrict,$type); if($r) { $c = q("select channel_address from channel where channel_id = %d limit 1", @@ -334,7 +341,7 @@ function get_things($profile_hash,$uid) { $sql_extra = (($profile_hash) ? " and obj_page = '" . $profile_hash . "' " : ''); - $r = q("select * from obj left join term on obj_obj = term_hash where term_hash != '' and uid = %d and obj_type = %d $sql_extra order by obj_verb, term", + $r = q("select * from obj where obj_channel = %d and obj_type = %d $sql_extra order by obj_verb, obj_term", intval($uid), intval(TERM_OBJ_THING) ); @@ -350,8 +357,8 @@ function get_things($profile_hash,$uid) { foreach($r as $rr) { $rr['profile_name'] = ''; - if(! in_array($rr['term_hash'],$profile_hashes)) - $profile_hashes[] = $rr['term_hash']; + if(! in_array($rr['obj_obj'],$profile_hashes)) + $profile_hashes[] = $rr['obj_obj']; } stringify_array_elms($profile_hashes); if(! $profile_hash) { @@ -383,7 +390,7 @@ function get_things($profile_hash,$uid) { $l = q("select xchan_name, xchan_url from likes left join xchan on likee = xchan_hash where target_type = '%s' and target_id = '%s' and channel_id = %d", dbesc(ACTIVITY_OBJ_THING), - dbesc($rr['term_hash']), + dbesc($rr['obj_obj']), intval($uid) ); @@ -393,7 +400,7 @@ function get_things($profile_hash,$uid) { if(! $things[$rr['obj_verb']]) $things[$rr['obj_verb']] = array(); - $things[$rr['obj_verb']][] = array('term' => $rr['term'],'url' => $rr['url'],'img' => $rr['imgurl'], 'profile' => $rr['profile_name'],'term_hash' => $rr['term_hash'], 'likes' => $l,'like_count' => count($l),'like_label' => tt('Like','Likes',count($l),'noun')); + $things[$rr['obj_verb']][] = array('term' => $rr['obj_term'],'url' => $rr['obj_url'],'img' => $rr['obj_imgurl'], 'profile' => $rr['profile_name'],'term_hash' => $rr['obj_obj'], 'likes' => $l,'like_count' => count($l),'like_label' => tt('Like','Likes',count($l),'noun')); } $sorted_things = array(); if($things) { diff --git a/include/text.php b/include/text.php index f4122845e..b1af62fc5 100644 --- a/include/text.php +++ b/include/text.php @@ -454,63 +454,7 @@ function alt_pager(&$a, $i, $more = '', $less = '') { } -/** - * @brief Turn user/group ACLs stored as angle bracketed text into arrays. - * - * turn string array of angle-bracketed elements into string array - * e.g. "<123xyz><246qyo><sxo33e>" => array(123xyz,246qyo,sxo33e); - * - * @param string $s - * @return array - */ -function expand_acl($s) { - $ret = array(); - if(strlen($s)) { - $t = str_replace('<','',$s); - $a = explode('>',$t); - foreach($a as $aa) { - if($aa) - $ret[] = $aa; - } - } - - return $ret; -} - -/** - * @brief Used to wrap ACL elements in angle brackets for storage. - * - * @param[in,out] array &$item - */ -function sanitise_acl(&$item) { - if (strlen($item)) - $item = '<' . notags(trim($item)) . '>'; - else - unset($item); -} - -/** - * @brief Convert an ACL array to a storable string. - * - * @param array $p - * @return array - */ -function perms2str($p) { - $ret = ''; - - if (is_array($p)) - $tmp = $p; - else - $tmp = explode(',', $p); - - if (is_array($tmp)) { - array_walk($tmp, 'sanitise_acl'); - $ret = implode('', $tmp); - } - - return $ret; -} /** * @brief Generate a guaranteed unique (for this domain) item ID for ATOM. @@ -575,9 +519,9 @@ function attribute_contains($attr, $s) { } /** - * @brief Logging function for RedMatrix. + * @brief Logging function for Hubzilla. * - * Logging output is configured through RedMatrix's system config. The log file + * Logging output is configured through Hubzilla's system config. The log file * is set in system logfile, log level in system loglevel and to enable logging * set system debugging. * @@ -743,7 +687,7 @@ function get_tags($s) { // make sure the longer tags are returned first so that if two or more have common substrings // we'll replace the longest ones first. Otherwise the common substring would be found in // both strings and the string replacement would link both to the shorter strings and - // fail to link the longer string. RedMatrix github issue #378 + // fail to link the longer string. Hubzilla github issue #378 usort($ret,'tag_sort_length'); @@ -808,20 +752,21 @@ function contact_block() { return; $is_owner = ((local_channel() && local_channel() == $a->profile['uid']) ? true : false); + $sql_extra = ''; + + $abook_flags = " and abook_pending = 0 and abook_self = 0 "; - $abook_flags = ABOOK_FLAG_PENDING|ABOOK_FLAG_SELF; - $xchan_flags = XCHAN_FLAGS_ORPHAN|XCHAN_FLAGS_DELETED; if(! $is_owner) { - $abook_flags = $abook_flags | ABOOK_FLAG_HIDDEN; - $xchan_flags = $xchan_flags | XCHAN_FLAGS_HIDDEN; + $abook_flags .= " and abook_hidden = 0 "; + $sql_extra = " and xchan_hidden = 0 "; } if((! is_array($a->profile)) || ($a->profile['hide_friends'])) return $o; - $r = q("SELECT COUNT(abook_id) AS total FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d and ( abook_flags & %d ) = 0 and ( xchan_flags & %d ) = 0", - intval($a->profile['uid']), - intval($abook_flags), - intval($xchan_flags) + + $r = q("SELECT COUNT(abook_id) AS total FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d + $abook_flags and xchan_orphan = 0 and xchan_deleted = 0 $sql_extra", + intval($a->profile['uid']) ); if(count($r)) { $total = intval($r[0]['total']); @@ -830,21 +775,19 @@ function contact_block() { $contacts = t('No connections'); $micropro = null; } else { - + $randfunc = db_getfunc('RAND'); - - $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash WHERE abook_channel = %d AND ( abook_flags & %d ) = 0 and ( xchan_flags & %d ) = 0 ORDER BY $randfunc LIMIT %d", - intval($a->profile['uid']), - intval($abook_flags|ABOOK_FLAG_ARCHIVED), - intval($xchan_flags), - intval($shown) + + $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash WHERE abook_channel = %d $abook_flags and abook_archived = 0 and xchan_orphan = 0 and xchan_deleted = 0 $sql_extra ORDER BY $randfunc LIMIT %d", + intval($a->profile['uid']), + intval($shown) ); if(count($r)) { $contacts = sprintf( tt('%d Connection','%d Connections', $total),$total); $micropro = Array(); foreach($r as $rr) { - $rr['archived'] = (($rr['abook_flags'] & ABOOK_FLAG_ARCHIVED) ? true : false); + $rr['archived'] = (intval($rr['abook_archived']) ? true : false); $micropro[] = micropro($rr,true,'mpfriend'); } } @@ -1241,17 +1184,16 @@ function link_compare($a, $b) { function unobscure(&$item) { - if(array_key_exists('item_flags',$item) && ($item['item_flags'] & ITEM_OBSCURED)) { + if(array_key_exists('item_obscured',$item) && intval($item['item_obscured'])) { $key = get_config('system','prvkey'); if($item['title']) $item['title'] = crypto_unencapsulate(json_decode_plus($item['title']),$key); if($item['body']) $item['body'] = crypto_unencapsulate(json_decode_plus($item['body']),$key); if(get_config('system','item_cache')) { - q("update item set title = '%s', body = '%s', item_flags = %d where id = %d", + q("update item set title = '%s', body = '%s', item_obscured = 0 where id = %d", dbesc($item['title']), dbesc($item['body']), - intval($item['item_flags'] - ITEM_OBSCURED), intval($item['id']) ); } @@ -1259,12 +1201,11 @@ function unobscure(&$item) { } function unobscure_mail(&$item) { - if(array_key_exists('mail_flags',$item) && ($item['mail_flags'] & MAIL_OBSCURED)) { - $key = get_config('system','prvkey'); + if(array_key_exists('mail_obscured',$item) && intval($item['mail_obscured'])) { if($item['title']) - $item['title'] = crypto_unencapsulate(json_decode_plus($item['title']),$key); + $item['title'] = base64url_decode(str_rot47($item['title'])); if($item['body']) - $item['body'] = crypto_unencapsulate(json_decode_plus($item['body']),$key); + $item['body'] = base64url_decode(str_rot47($item['body'])); } } @@ -1304,7 +1245,7 @@ function theme_attachments(&$item) { $title = htmlspecialchars($r['title'], ENT_COMPAT,'UTF-8'); if(! $title) $title = t('unknown.???'); - $title .= ' ' . $r['length'] . ' ' . t('bytes'); + $title .= ' ' . (($r['length']) ? $r['length'] . ' ' . t('bytes') : ''); require_once('include/identity.php'); if(is_foreigner($item['author_xchan'])) @@ -1441,16 +1382,24 @@ function generate_named_map($location) { function prepare_body(&$item,$attach = false) { - call_hooks('prepare_body_init', $item); - - unobscure($item); - - $s = prepare_text($item['body'],$item['mimetype']); +// if($item['html']) { +// $s = bb_observer($item['html']); +// } +// else { + call_hooks('prepare_body_init', $item); +// unobscure($item); + $s = prepare_text($item['body'],$item['mimetype'], false); +// } $prep_arr = array('item' => $item, 'html' => $s); call_hooks('prepare_body', $prep_arr); $s = $prep_arr['html']; +// q("update item set html = '%s' where id = %d", +// dbesc($s), +// intval($item['id']) +// ); + if(! $attach) { return $s; } @@ -1509,7 +1458,6 @@ function prepare_body(&$item,$attach = false) { $prep_arr = array('item' => $item, 'html' => $s); call_hooks('prepare_body_final', $prep_arr); - return $prep_arr['html']; } @@ -1520,7 +1468,7 @@ function prepare_body(&$item,$attach = false) { * @param sting $content_type * @return string */ -function prepare_text($text, $content_type = 'text/bbcode') { +function prepare_text($text, $content_type = 'text/bbcode', $cache = false) { switch($content_type) { case 'text/plain': @@ -1558,9 +1506,9 @@ function prepare_text($text, $content_type = 'text/bbcode') { require_once('include/bbcode.php'); if(stristr($text,'[nosmile]')) - $s = bbcode($text); + $s = bbcode($text,false,true,$cache); else - $s = smilies(bbcode($text)); + $s = smilies(bbcode($text,false,true,$cache)); $s = zidify_links($s); break; } @@ -1672,9 +1620,9 @@ function unamp($s) { } function layout_select($channel_id, $current = '') { - $r = q("select mid,sid from item left join item_id on iid = item.id where service = 'PDL' and item.uid = item_id.uid and item_id.uid = %d and (item_restrict & %d)>0", + $r = q("select mid,sid from item left join item_id on iid = item.id where service = 'PDL' and item.uid = item_id.uid and item_id.uid = %d and item_type = %d ", intval($channel_id), - intval(ITEM_PDL) + intval(ITEM_TYPE_PDL) ); if($r) { @@ -1738,14 +1686,14 @@ function mimetype_select($channel_id, $current = 'text/bbcode') { function lang_selector() { global $a; - $langs = glob('view/*/strings.php'); + $langs = glob('view/*/hstrings.php'); $lang_options = array(); $selected = ""; if(is_array($langs) && count($langs)) { $langs[] = ''; - if(! in_array('view/en/strings.php',$langs)) + if(! in_array('view/en/hstrings.php',$langs)) $langs[] = 'view/en/'; asort($langs); foreach($langs as $l) { @@ -2027,13 +1975,13 @@ function xchan_query(&$items,$abook = true,$effective_uid = 0) { 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 and abook_channel = %d - where xchan_hash in (" . implode(',', $arr) . ") and ( hubloc_flags & " . intval(HUBLOC_FLAGS_PRIMARY) . " )>0", + where xchan_hash in (" . implode(',', $arr) . ") and hubloc_primary = 1", intval($item['uid']) ); } else { $chans = q("select xchan.*,hubloc.* from xchan left join hubloc on hubloc_hash = xchan_hash - where xchan_hash in (" . implode(',', $arr) . ") and ( hubloc_flags & " . intval(HUBLOC_FLAGS_PRIMARY) . " )>0"); + where xchan_hash in (" . implode(',', $arr) . ") and hubloc_primary = 1"); } $xchans = q("select * from xchan where xchan_hash in (" . implode(',',$arr) . ") and xchan_network in ('rss','unknown')"); if(! $chans) @@ -2061,7 +2009,7 @@ function xchan_mail_query(&$item) { if(count($arr)) { $chans = q("select xchan.*,hubloc.* from xchan left join hubloc on hubloc_hash = xchan_hash - where xchan_hash in (" . implode(',', $arr) . ") and ( hubloc_flags & " . intval(HUBLOC_FLAGS_PRIMARY) . " )>0"); + where xchan_hash in (" . implode(',', $arr) . ") and hubloc_primary = 1"); } if($chans) { $item['from'] = find_xchan_in_array($item['from_xchan'],$chans); @@ -2610,3 +2558,9 @@ function userReadableSize($size) { return $ret; } + +function str_rot47($str) { + return strtr($str, + '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~', + 'PQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO'); +} diff --git a/include/widgets.php b/include/widgets.php index 032b1c67e..9c8596a66 100644 --- a/include/widgets.php +++ b/include/widgets.php @@ -29,7 +29,7 @@ function widget_tagcloud($args) { $type = TERM_CATEGORY; // FIXME there exists no $authors variable - $r = tagadelic($uid, $count, $authors, $flags, ITEM_WEBPAGE, $type); + $r = tagadelic($uid, $count, $authors, $owner, $flags, ITEM_TYPE_WEBPAGE, $type); if($r) { $o = '<div class="tagblock widget"><h3>' . t('Categories') . '</h3><div class="tags" align="center">'; @@ -155,9 +155,8 @@ function widget_follow($args) { $a = get_app(); $uid =$a->channel['channel_id']; - $r = q("select count(*) as total from abook where abook_channel = %d and not (abook_flags & %d)>0 ", - intval($uid), - intval(ABOOK_FLAG_SELF) + $r = q("select count(*) as total from abook where abook_channel = %d and abook_self = 0 ", + intval($uid) ); if($r) $total_channels = $r[0]['total']; @@ -394,7 +393,7 @@ function widget_tagcloud_wall($arr) { $limit = ((array_key_exists('limit', $arr)) ? intval($arr['limit']) : 50); if(feature_enabled($a->profile['profile_uid'], 'tagadelic')) - return wtagblock($a->profile['profile_uid'], $limit, $a->profile['channel_hash'], ITEM_WALL); + return wtagblock($a->profile['profile_uid'], $limit, '', $a->profile['channel_hash'], 'wall'); return ''; } @@ -409,8 +408,7 @@ function widget_catcloud_wall($arr) { $limit = ((array_key_exists('limit',$arr)) ? intval($arr['limit']) : 50); - return catblock($a->profile['profile_uid'], $limit, $a->profile['channel_hash'], ITEM_WALL); - + return catblock($a->profile['profile_uid'], $limit, '', $a->profile['channel_hash'], 'wall'); } @@ -475,9 +473,8 @@ function widget_settings_menu($arr) { $role = get_pconfig(local_channel(),'system','permissions_role'); - $abk = q("select abook_id from abook where abook_channel = %d and ( abook_flags & %d )>0 limit 1", - intval(local_channel()), - intval(ABOOK_FLAG_SELF) + $abk = q("select abook_id from abook where abook_channel = %d and abook_self = 1 limit 1", + intval(local_channel()) ); if($abk) $abook_self_id = $abk[0]['abook_id']; @@ -565,14 +562,30 @@ function widget_mailmenu($arr) { return; $a = get_app(); + return replace_macros(get_markup_template('message_side.tpl'), array( - '$title' => t('Messages'), - '$tabs'=> array(), + '$title' => t('Private Mail Menu'), '$check'=>array( 'label' => t('Check Mail'), - 'url' => $a->get_baseurl(true) . '/message', + 'url' => $a->get_baseurl(true) . '/mail/combined', 'sel' => (argv(1) == ''), ), + + '$combined'=>array( + 'label' => t('Combined View'), + 'url' => $a->get_baseurl(true) . '/mail/combined', + 'sel' => (argv(1) == 'combined'), + ), + '$inbox'=>array( + 'label' => t('Inbox'), + 'url' => $a->get_baseurl(true) . '/mail/inbox', + 'sel' => (argv(1) == 'inbox'), + ), + '$outbox'=>array( + 'label' => t('Outbox'), + 'url' => $a->get_baseurl(true) . '/mail/outbox', + 'sel' => (argv(1) == 'outbox'), + ), '$new'=>array( 'label' => t('New Message'), 'url' => $a->get_baseurl(true) . '/mail/new', @@ -581,6 +594,80 @@ function widget_mailmenu($arr) { )); } + +function widget_conversations($arr) { + if (! local_channel()) + return; + + $a = get_app(); + + if(argc() > 1) { + + switch(argv(1)) { + case 'combined': + $mailbox = 'combined'; + $header = t('Conversations'); + break; + case 'inbox': + $mailbox = 'inbox'; + $header = t('Received Messages'); + break; + case 'outbox': + $mailbox = 'outbox'; + $header = t('Sent Messages'); + break; + default: + $mailbox = 'combined'; + $header = t('Conversations'); + break; + } + + require_once('include/message.php'); + + // private_messages_list() can do other more complicated stuff, for now keep it simple + $r = private_messages_list(local_channel(), $mailbox, $a->pager['start'], $a->pager['itemspage']); + + if(! $r) { + info( t('No messages.') . EOL); + return $o; + } + + $messages = array(); + + foreach($r as $rr) { + + $messages[] = array( + 'mailbox' => $mailbox, + 'id' => $rr['id'], + 'from_name' => $rr['from']['xchan_name'], + 'from_url' => chanlink_hash($rr['from_xchan']), + 'from_photo' => $rr['from']['xchan_photo_s'], + 'to_name' => $rr['to']['xchan_name'], + 'to_url' => chanlink_hash($rr['to_xchan']), + 'to_photo' => $rr['to']['xchan_photo_s'], + 'subject' => (($rr['seen']) ? $rr['title'] : '<strong>' . $rr['title'] . '</strong>'), + 'delete' => t('Delete conversation'), + 'body' => $rr['body'], + 'date' => datetime_convert('UTC',date_default_timezone_get(),$rr['created'], t('D, d M Y - g:i A')), + 'seen' => $rr['seen'], + 'selected' => ((argv(2)) ? (argv(2) == $rr['id']) : ($r[0]['id'] == $rr['id'])) + ); + } + + $tpl = get_markup_template('mail_head.tpl'); + $o .= replace_macros($tpl, array( + '$header' => $header, + '$messages' => $messages + )); + + $o .= alt_pager($a,count($r)); + + } + + return $o; +} + + function widget_design_tools($arr) { $a = get_app(); @@ -597,6 +684,7 @@ function widget_design_tools($arr) { return design_tools(); } + function widget_findpeople($arr) { return findpeople_widget(); } @@ -608,7 +696,7 @@ function widget_photo_albums($arr) { if(! $a->profile['profile_uid']) return ''; $channelx = channelx_by_n($a->profile['profile_uid']); - if((! $channelx) || (! perm_is_allowed($a->profile['profile_uid'], get_observer_hash(), 'view_photos'))) + if((! $channelx) || (! perm_is_allowed($a->profile['profile_uid'], get_observer_hash(), 'view_storage'))) return ''; require_once('include/photos.php'); @@ -706,7 +794,7 @@ function widget_item($arr) { require_once('include/security.php'); $sql_extra = item_permissions_sql($uid); - $r = q("select * from item where mid = '%s' and uid = %d and item_restrict = " . intval(ITEM_WEBPAGE) . " $sql_extra limit 1", + $r = q("select * from item where mid = '%s' and uid = %d and item_type = " . intval(ITEM_TYPE_WEBPAGE) . " $sql_extra limit 1", dbesc($arr['mid']), intval($uid) ); @@ -904,10 +992,10 @@ function widget_random_block($arr) { $r = q("select item.* from item left join item_id on item.id = item_id.iid where item.uid = %d and sid like '%s' and service = 'BUILDBLOCK' and - item_restrict = %d $sql_options order by $randfunc limit 1", + item_type = %d $sql_options order by $randfunc limit 1", intval($channel_id), dbesc('%' . $contains . '%'), - intval(ITEM_BUILDBLOCK) + intval(ITEM_TYPE_BLOCK) ); if($r) { @@ -983,8 +1071,159 @@ function widget_rating($arr) { } // used by site ratings pages to provide a return link -function widget_pubsites() { +function widget_pubsites($arr) { if(get_app()->poi) return; return '<div class="widget"><ul class="nav nav-pills"><li><a href="pubsites">' . t('Public Hubs') . '</a></li></ul></div>'; } + + +function widget_forums($arr) { + + $a = get_app(); + + if(! local_channel()) + return ''; + + $o = ''; + + if(is_array($arr) && array_key_exists('limit',$arr)) + $limit = " limit " . intval($limit) . " "; + else + $limit = ''; + + $unseen = 0; + if(is_array($arr) && array_key_exists('unseen',$arr) && intval($arr['unseen'])) + $unseen = 1; + + $perms_sql = item_permissions_sql(local_channel()) . item_normal(); + + $r1 = q("select * from abook left join xchan on abook_xchan = xchan_hash where ( xchan_pubforum = 1 or ((abook_their_perms & %d ) != 0 and (abook_their_perms & %d ) = 0) ) and abook_channel = %d order by xchan_name $limit ", + intval(PERMS_W_TAGWALL), + intval(PERMS_W_STREAM), + intval(local_channel()) + ); + if(! $r1) + return $o; + + $str = ''; + + // Trying to cram all this into a single query with joins and the proper group by's is tough. + // There also should be a way to update this via ajax. + + for($x = 0; $x < count($r1); $x ++) { + $r = q("select sum(item_unseen) as unseen from item where owner_xchan = '%s' and uid = %d $perms_sql ", + dbesc($r1[$x]['xchan_hash']), + intval(local_channel()) + ); + if($r) + $r1[$x]['unseen'] = $r[0]['unseen']; + } + + if($r1) { + $o .= '<div class="widget">'; + $o .= '<h3>' . t('Forums') . '</h3><ul class="nav nav-pills nav-stacked">'; + + foreach($r1 as $rr) { + if($unseen && (! intval($rr['unseen']))) + continue; + $o .= '<li><span class="pull-right">' . ((intval($rr['unseen'])) ? intval($rr['unseen']) : '') . '</span><a href="network?f=&pf=1&cid=' . $rr['abook_id'] . '" ><img src="' . $rr['xchan_photo_s'] . '" style="width: 16px; height: 16px;" /> ' . $rr['xchan_name'] . '</a></li>'; + } + $o .= '</ul></div>'; + } + return $o; + +} + + +function widget_tasklist($arr) { + + + require_once('include/event.php'); + $o .= '<script>var tasksShowAll = 0; $(document).ready(function() { tasksFetch(); $("#tasklist-new-form").submit(function(event) { event.preventDefault(); $.post( "tasks/new", $("#tasklist-new-form").serialize(), function(data) { tasksFetch(); $("#tasklist-new-summary").val(""); } ); return false; } )});</script>'; + $o .= '<script>function taskComplete(id) { $.post("tasks/complete/"+id, function(data) { tasksFetch();}); } + function tasksFetch() { + $.get("tasks/fetch" + ((tasksShowAll) ? "/all" : ""), function(data) { + $(".tasklist-tasks").html(data.html); + }); + } + </script>'; + + $o .= '<div class="widget">' . '<h3>' . t('Tasks') . '</h3><div class="tasklist-tasks">'; + $o .= '</div><form id="tasklist-new-form" action="" ><input id="tasklist-new-summary" type="text" name="summary" value="" /></form>'; + $o .= '</div>'; + return $o; + +} + + +function widget_helpindex($arr) { + $o .= '<div class="widget">' . '<h3>' . t('Documentation') . '</h3>'; + $o .= '<ul class="nav nav-pills nav-stacked">'; + $o .= '<li><a href="help/general">' . t('Project/Site Information') . '</a></li>'; + $o .= '<li><a href="help/members">' . t('For Members') . '</a></li>'; + $o .= '<li><a href="help/admins">' . t('For Administrators') . '</a></li>'; + $o .= '<li><a href="help/develop">' . t('For Developers') . '</a></li>'; + $o .= '</ul></div>'; + return $o; + +} + + + +function widget_admin($arr) { + + /* + * Side bar links + */ + + if(! is_site_admin()) { + return login(false); + } + + + $a = get_app(); + $o = ''; + + // array( url, name, extra css classes ) + + $aside = array( + 'site' => array(z_root() . '/admin/site/', t('Site'), 'site'), + 'users' => array(z_root() . '/admin/users/', t('Accounts'), 'users'), + 'channels' => array(z_root() . '/admin/channels/', t('Channels'), 'channels'), + 'plugins' => array(z_root() . '/admin/plugins/', t('Plugins'), 'plugins'), + 'themes' => array(z_root() . '/admin/themes/', t('Themes'), 'themes'), + 'queue' => array(z_root() . '/admin/queue', t('Inspect queue'), 'queue'), + 'profs' => array(z_root() . '/admin/profs', t('Profile Config'), 'profs'), + 'dbsync' => array(z_root() . '/admin/dbsync/', t('DB updates'), 'dbsync') + + ); + + /* get plugins admin page */ + + $r = q("SELECT * FROM addon WHERE plugin_admin = 1"); + + $aside['plugins_admin'] = array(); + if($r) { + foreach ($r as $h){ + $plugin = $h['name']; + $aside['plugins_admin'][] = array(z_root() . '/admin/plugins/' . $plugin, $plugin, 'plugin'); + // temp plugins with admin + $a->plugins_admin[] = $plugin; + } + } + + $aside['logs'] = array(z_root() . '/admin/logs/', t('Logs'), 'logs'); + + $o .= replace_macros(get_markup_template('admin_aside.tpl'), array( + '$admin' => $aside, + '$admtxt' => t('Admin'), + '$plugadmtxt' => t('Plugin Features'), + '$logtxt' => t('Logs'), + '$h_pending' => t('User registrations waiting for confirmation'), + '$admurl'=> z_root() . '/admin/' + )); + + return $o; + +} diff --git a/include/zot.php b/include/zot.php index fe51d1a7c..e9132b7a5 100644 --- a/include/zot.php +++ b/include/zot.php @@ -1,7 +1,7 @@ <?php /** * @file include/zot.php - * @brief RedMatrix implementation of zot protocol. + * @brief Hubzilla implementation of zot protocol. * * https://github.com/friendica/red/wiki/zot * https://github.com/friendica/red/wiki/Zot---A-High-Level-Overview @@ -80,9 +80,8 @@ function zot_get_hublocs($hash) { /* Only search for active hublocs - e.g. those that haven't been marked deleted */ - $ret = q("select * from hubloc where hubloc_hash = '%s' and not ( hubloc_flags & %d )>0 order by hubloc_url ", - dbesc($hash), - intval(HUBLOC_FLAGS_DELETED) + $ret = q("select * from hubloc where hubloc_hash = '%s' and hubloc_deleted = 0 order by hubloc_url ", + dbesc($hash) ); return $ret; @@ -200,9 +199,8 @@ function zot_finger($webbie, $channel = null, $autofallback = true) { $r = q("select xchan.*, hubloc.* from xchan left join hubloc on xchan_hash = hubloc_hash - where xchan_addr = '%s' and (hubloc_flags & %d) > 0 limit 1", - dbesc($xchan_addr), - intval(HUBLOC_FLAGS_PRIMARY) + where xchan_addr = '%s' and hubloc_primary = 1 limit 1", + dbesc($xchan_addr) ); if ($r) { @@ -298,19 +296,24 @@ function zot_refresh($them, $channel = null, $force = false) { } else { $r = null; + // if they re-installed the server we could end up with the wrong record - pointing to the old install. + // We'll order by reverse id to try and pick off the newest one first and hopefully end up with the + // correct hubloc. If this doesn't work we may have to re-write this section to try them all. + if(array_key_exists('xchan_addr',$them) && $them['xchan_addr']) { - $r = q("select hubloc_url, hubloc_flags from hubloc where hubloc_addr = '%s'", + $r = q("select hubloc_url, hubloc_primary from hubloc where hubloc_addr = '%s' order by hubloc_id desc", dbesc($them['xchan_addr']) ); } if(! $r) { - $r = q("select hubloc_url, hubloc_flags from hubloc where hubloc_hash = '%s'", + $r = q("select hubloc_url, hubloc_primary from hubloc where hubloc_hash = '%s' order by hubloc_id desc", dbesc($them['xchan_hash']) ); } + if ($r) { foreach ($r as $rr) { - if ($rr['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY) { + if (intval($rr['hubloc_primary'])) { $url = $rr['hubloc_url']; break; } @@ -402,10 +405,9 @@ function zot_refresh($them, $channel = null, $force = false) { $next_birthday = NULL_DATE; } - $r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d and not (abook_flags & %d) > 0 limit 1", + $r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1", dbesc($x['hash']), - intval($channel['channel_id']), - intval(ABOOK_FLAG_SELF) + intval($channel['channel_id']) ); if($r) { @@ -419,16 +421,15 @@ function zot_refresh($them, $channel = null, $force = false) { if(substr($r[0]['abook_dob'],5) == substr($next_birthday,5)) $next_birthday = $r[0]['abook_dob']; - $current_abook_connected = (($r[0]['abook_flags'] & ABOOK_FLAG_UNCONNECTED) ? 0 : 1); + $current_abook_connected = (intval($r[0]['abook_unconnected']) ? 0 : 1); $y = q("update abook set abook_their_perms = %d, abook_dob = '%s' where abook_xchan = '%s' and abook_channel = %d - and not (abook_flags & %d) > 0 ", + and abook_self = 0 ", intval($their_perms), dbescdate($next_birthday), dbesc($x['hash']), - intval($channel['channel_id']), - intval(ABOOK_FLAG_SELF) + intval($channel['channel_id']) ); // if(($connected_set === 0 || $connected_set === 1) && ($connected_set !== $current_abook_unconnected)) { @@ -437,13 +438,11 @@ function zot_refresh($them, $channel = null, $force = false) { // match your current connected state setting, toggle it. /** @FIXME uncoverted to postgres */ /** @FIXME when this was enabled, all contacts became unconnected. Currently disabled intentionally */ -// $y1 = q("update abook set abook_flags = (abook_flags ^ %d) +// $y1 = q("update abook set abook_unconnected = 1 // where abook_xchan = '%s' and abook_channel = %d -// and not (abook_flags & %d) limit 1", -// intval(ABOOK_FLAG_UNCONNECTED), +// and abook_self = 0 limit 1", // dbesc($x['hash']), -// intval($channel['channel_id']), -// intval(ABOOK_FLAG_SELF) +// intval($channel['channel_id']) // ); // } @@ -477,7 +476,7 @@ function zot_refresh($them, $channel = null, $force = false) { if($closeness === false) $closeness = 80; - $y = q("insert into abook ( abook_account, abook_channel, abook_closeness, abook_xchan, abook_their_perms, abook_my_perms, abook_created, abook_updated, abook_dob, abook_flags ) values ( %d, %d, %d, '%s', %d, %d, '%s', '%s', '%s', %d )", + $y = q("insert into abook ( abook_account, abook_channel, abook_closeness, abook_xchan, abook_their_perms, abook_my_perms, abook_created, abook_updated, abook_dob, abook_pending ) values ( %d, %d, %d, '%s', %d, %d, '%s', '%s', '%s', %d )", intval($channel['channel_account_id']), intval($channel['channel_id']), intval($closeness), @@ -487,7 +486,7 @@ function zot_refresh($them, $channel = null, $force = false) { dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($next_birthday), - intval(($default_perms) ? 0 : ABOOK_FLAG_PENDING) + intval(($default_perms) ? 0 : 1) ); if($y) { @@ -496,10 +495,9 @@ function zot_refresh($them, $channel = null, $force = false) { // Send a clone sync packet and a permissions update if permissions have changed - $new_connection = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d and not (abook_flags & %d) > 0 order by abook_created desc limit 1", + $new_connection = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 order by abook_created desc limit 1", dbesc($x['hash']), - intval($channel['channel_id']), - intval(ABOOK_FLAG_SELF) + intval($channel['channel_id']) ); if($new_connection) { @@ -515,7 +513,7 @@ function zot_refresh($them, $channel = null, $force = false) { if($their_perms & PERMS_R_STREAM) { if(($channel['channel_w_stream'] & PERMS_PENDING) - || (! ($new_connection[0]['abook_flags'] & ABOOK_FLAG_PENDING)) ) + || (! intval($new_connection[0]['abook_pending'])) ) proc_run('php','include/onepoll.php',$new_connection[0]['abook_id']); } @@ -591,7 +589,7 @@ function zot_gethub($arr,$multiple = false) { } /** - * @brief Registers an unknown hup. + * @brief Registers an unknown hub. * * A communication has been received which has an unknown (to us) sender. * Perform discovery based on our calculated hash of the sender at the @@ -727,43 +725,36 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { $hidden = (1 - intval($arr['searchable'])); - // Be careful - XCHAN_FLAGS_HIDDEN should evaluate to 1 - if(($r[0]['xchan_flags'] & XCHAN_FLAGS_HIDDEN) != $hidden) - $new_flags = $r[0]['xchan_flags'] ^ XCHAN_FLAGS_HIDDEN; - else - $new_flags = $r[0]['xchan_flags']; - - $adult = (($r[0]['xchan_flags'] & XCHAN_FLAGS_SELFCENSORED) ? true : false); - $adult_changed = ((intval($adult) != intval($arr['adult_content'])) ? true : false); - if($adult_changed) - $new_flags = $new_flags ^ XCHAN_FLAGS_SELFCENSORED; - - $deleted = (($r[0]['xchan_flags'] & XCHAN_FLAGS_DELETED) ? true : false); - $deleted_changed = ((intval($deleted) != intval($arr['deleted'])) ? true : false); - if($deleted_changed) - $new_flags = $new_flags ^ XCHAN_FLAGS_DELETED; - - $public_forum = (($r[0]['xchan_flags'] & XCHAN_FLAGS_PUBFORUM) ? true : false); - $pubforum_changed = ((intval($public_forum) != intval($arr['public_forum'])) ? true : false); - if($pubforum_changed) - $new_flags = $r[0]['xchan_flags'] ^ XCHAN_FLAGS_PUBFORUM; - - if(($r[0]['xchan_name_date'] != $arr['name_updated']) - || ($r[0]['xchan_connurl'] != $arr['connections_url']) - || ($r[0]['xchan_flags'] != $new_flags) + $hidden_changed = $adult_changed = $deleted_changed = $pubforum_changed = 0; + + if(intval($r[0]['xchan_hidden']) != (1 - intval($arr['searchable']))) + $hidden_changed = 1; + if(intval($r[0]['xchan_selfcensored']) != intval($arr['adult_content'])) + $adult_changed = 1; + if(intval($r[0]['xchan_deleted']) != intval($arr['deleted'])) + $deleted_changed = 1; + if(intval($r[0]['xchan_pubforum']) != intval($arr['public_forum'])) + $pubforum_changed = 1; + + if(($r[0]['xchan_name_date'] != $arr['name_updated']) + || ($r[0]['xchan_connurl'] != $arr['connections_url']) || ($r[0]['xchan_addr'] != $arr['address']) || ($r[0]['xchan_follow'] != $arr['follow_url']) - || ($r[0]['xchan_connpage'] != $arr['connect_url']) - || ($r[0]['xchan_url'] != $arr['url'])) { - $r = q("update xchan set xchan_name = '%s', xchan_name_date = '%s', xchan_connurl = '%s', xchan_follow = '%s', - xchan_connpage = '%s', xchan_flags = %d, + || ($r[0]['xchan_connpage'] != $arr['connect_url']) + || ($r[0]['xchan_url'] != $arr['url']) + || $hidden_changed || adult_changed || deleted_changed || $pubforum_changed ) { + $r = q("update xchan set xchan_name = '%s', xchan_name_date = '%s', xchan_connurl = '%s', xchan_follow = '%s', + xchan_connpage = '%s', xchan_hidden = %d, xchan_selfcensored = %d, xchan_deleted = %d, xchan_pubforum = %d, xchan_addr = '%s', xchan_url = '%s' where xchan_hash = '%s'", dbesc(($arr['name']) ? $arr['name'] : '-'), dbesc($arr['name_updated']), dbesc($arr['connections_url']), dbesc($arr['follow_url']), dbesc($arr['connect_url']), - intval($new_flags), + intval(1 - intval($arr['searchable'])), + intval($arr['adult_content']), + intval($arr['deleted']), + intval($arr['public_forum']), dbesc($arr['address']), dbesc($arr['url']), dbesc($xchan_hash) @@ -782,20 +773,9 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { && ($arr['site']['url'] != z_root())) $arr['searchable'] = false; - $hidden = (1 - intval($arr['searchable'])); - - if($hidden) - $new_flags = XCHAN_FLAGS_HIDDEN; - else - $new_flags = 0; - if($arr['adult_content']) - $new_flags |= XCHAN_FLAGS_SELFCENSORED; - if(array_key_exists('deleted',$arr) && $arr['deleted']) - $new_flags |= XCHAN_FLAGS_DELETED; - $x = q("insert into xchan ( xchan_hash, xchan_guid, xchan_guid_sig, xchan_pubkey, xchan_photo_mimetype, - xchan_photo_l, xchan_addr, xchan_url, xchan_connurl, xchan_follow, xchan_connpage, xchan_name, xchan_network, xchan_photo_date, xchan_name_date, xchan_flags) - values ( '%s', '%s', '%s', '%s' , '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d) ", + xchan_photo_l, xchan_addr, xchan_url, xchan_connurl, xchan_follow, xchan_connpage, xchan_name, xchan_network, xchan_photo_date, xchan_name_date, xchan_hidden, xchan_selfcensored, xchan_deleted, xchan_pubforum ) + values ( '%s', '%s', '%s', '%s' , '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d) ", dbesc($xchan_hash), dbesc($arr['guid']), dbesc($arr['guid_sig']), @@ -811,7 +791,10 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { dbesc('zot'), dbescdate($arr['photo_updated']), dbescdate($arr['name_updated']), - intval($new_flags) + intval(1 - intval($arr['searchable'])), + intval($arr['adult_content']), + intval($arr['deleted']), + intval($arr['public_forum']) ); $what .= 'new_xchan'; @@ -841,7 +824,7 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { ); } } else { - $photos = import_profile_photo($arr['photo'], $xchan_hash); + $photos = import_xchan_photo($arr['photo'], $xchan_hash); } if ($photos) { if ($photos[4]) { @@ -979,9 +962,28 @@ function zot_process_response($hub, $arr, $outq) { logger('zot_process_response: headers: ' . print_r($arr['header'],true), LOGGER_DATA); } + if(is_array($x) && array_key_exists('delivery_report',$x) && is_array($x['delivery_report'])) { + foreach($x['delivery_report'] as $xx) { + if(is_array($xx) && array_key_exists('message_id',$xx)) { + q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan ) values ( '%s', '%s','%s','%s','%s','%s' ) ", + dbesc($xx['message_id']), + dbesc($xx['location']), + dbesc($xx['recipient']), + dbesc($xx['status']), + dbesc(datetime_convert($xx['date'])), + dbesc($xx['sender']) + ); + } + } + } + + q("delete from dreport where dreport_queue = '%s' limit 1", + dbesc($outq['outq_hash']) + ); + // update the timestamp for this site - q("update site set site_update = '%s' where site_url = '%s'", + q("update site set site_dead = 0, site_update = '%s' where site_url = '%s'", dbesc(datetime_convert()), dbesc(dirname($hub)) ); @@ -1149,14 +1151,15 @@ function zot_import($arr, $sender_url) { $recip_arr[] = make_xchan_hash($recip['guid'],$recip['guid_sig']); } } + $r = false; if($recip_arr) { stringify_array_elms($recip_arr); $recips = implode(',',$recip_arr); - $r = q("select channel_hash as hash from channel where channel_hash in ( " . $recips . " ) and not ( channel_pageflags & %d ) > 0 ", - intval(PAGE_REMOVED) - ); + $r = q("select channel_hash as hash from channel where channel_hash in ( " . $recips . " ) + and channel_removed = 0 "); } + if(! $r) { logger('recips: no recipients on this site'); continue; @@ -1234,8 +1237,10 @@ function zot_import($arr, $sender_url) { if($i['message']['type'] === 'activity') { $arr = get_item_elements($i['message']); - if(! array_key_exists('created',$arr)) { - logger('Activity rejected: probable failure to lookup author/owner. ' . print_r($i['message'],true)); + $v = validate_item_elements($i['message'],$arr); + + if(! $v['success']) { + logger('Activity rejected: ' . $v['message'] . ' ' . print_r($i['message'],true)); continue; } @@ -1371,13 +1376,13 @@ function public_recips($msg) { or ( " . $col . " & " . intval(PERMS_PUBLIC) . ") > 0 or ( " . $col . " & " . intval(PERMS_AUTHED) . ") > 0 ) "; } else { - $sql = " where (( " . $col . " & " . intval(PERMS_NETWORK) . " ) > 0 - or ( " . $col . " & " . intval(PERMS_PUBLIC) . ") > 0 - or ( " . $col . " & " . intval(PERMS_AUTHED) . ") > 0 ) "; + $sql = " where ( " . $col . " = " . intval(PERMS_NETWORK) . " + or " . $col . " = " . intval(PERMS_PUBLIC) . " + or " . $col . " = " . intval(PERMS_AUTHED) . " ) "; } $r = q("select channel_hash as hash from channel $sql or channel_hash = '%s' - and ( channel_pageflags & " . intval(PAGE_REMOVED) . " ) = 0 ", + and channel_removed = 0 ", dbesc($msg['notify']['sender']['hash']) ); @@ -1388,10 +1393,10 @@ function public_recips($msg) { // and is allowing this sender at least at a high level. $x = q("select channel_hash as hash from channel left join abook on abook_channel = channel_id - where abook_xchan = '%s' and ( channel_pageflags & " . intval(PAGE_REMOVED) . " ) = 0 - and (( " . $col . " & " . intval(PERMS_SPECIFIC) . " ) > 0 and ( abook_my_perms & " . intval($field) . " ) > 0 ) - OR ( " . $col . " & " . intval(PERMS_PENDING) . " ) > 0 - OR (( " . $col . " & " . intval(PERMS_CONTACTS) . " ) > 0 and ( abook_flags & " . intval(ABOOK_FLAG_PENDING) . " ) = 0 ) ", + where abook_xchan = '%s' and channel_removed = 0 + and (( " . $col . " = " . intval(PERMS_SPECIFIC) . " and ( abook_my_perms & " . intval($field) . " ) > 0 ) + OR " . $col . " = " . intval(PERMS_PENDING) . " + OR ( " . $col . " = " . intval(PERMS_CONTACTS) . " and abook_pending = 0 )) ", dbesc($msg['notify']['sender']['hash']) ); @@ -1420,7 +1425,7 @@ function public_recips($msg) { $address = basename($tag['url']); if($address) { $z = q("select channel_hash as hash from channel where channel_address = '%s' - and ( channel_pageflags & " . intval(PAGE_REMOVED) . " ) = 0 limit 1", + and channel_removed = 0 limit 1", dbesc($address) ); if($z) @@ -1438,8 +1443,7 @@ function public_recips($msg) { if($msg['message']['message_top']) { $z = q("select owner_xchan as hash from item where parent_mid = '%s' ", - dbesc($msg['message']['message_top']), - intval(ITEM_UPLINK) + dbesc($msg['message']['message_top']) ); if($z) $r = array_merge($r,$z); @@ -1524,9 +1528,8 @@ function allowed_public_recips($msg) { $condensed_recips[] = $rr['hash']; $results = array(); - $r = q("select channel_hash as hash from channel left join abook on abook_channel = channel_id where abook_xchan = '%s' and ( channel_pageflags & %d ) = 0 ", - dbesc($hash), - intval(PAGE_REMOVED) + $r = q("select channel_hash as hash from channel left join abook on abook_channel = channel_id where abook_xchan = '%s' and channel_removed = 0 ", + dbesc($hash) ); if($r) { foreach($r as $rr) @@ -1602,19 +1605,18 @@ logger('sender: ' . print_r($sender,true)); // continue; // } - // allow public postings to the sys channel regardless of permissions, but not // for comments travelling upstream. Wait and catch them on the way down. // They may have been blocked by the owner. - if(($channel['channel_pageflags'] & PAGE_SYSTEM) && (! $arr['item_private']) && (! $relay)) { + if(intval($channel['channel_system']) && (! $arr['item_private']) && (! $relay)) { $local_public = true; - $r = q("select xchan_flags from xchan where xchan_hash = '%s' limit 1", + $r = q("select xchan_selfcensored from xchan where xchan_hash = '%s' limit 1", dbesc($sender['hash']) ); // don't import sys channel posts from selfcensored authors - if($r && ($r[0]['xchan_flags'] & XCHAN_FLAGS_SELFCENSORED)) { + if($r && (intval($r[0]['xchan_selfcensored']))) { $local_public = false; continue; } @@ -1629,13 +1631,10 @@ logger('sender: ' . print_r($sender,true)); // This is our own post, possibly coming from a channel clone if($arr['owner_xchan'] == $d['hash']) { - $arr['item_flags'] = $arr['item_flags'] | ITEM_WALL; + $arr['item_wall'] = 1; } else { - // clear the wall flag if it is set - if($arr['item_flags'] & ITEM_WALL) { - $arr['item_flags'] = ($arr['item_flags'] ^ ITEM_WALL); - } + $arr['item_wall'] = 0; } if((! perm_is_allowed($channel['channel_id'],$sender['hash'],$perm)) && (! $tag_delivery) && (! $local_public)) { @@ -1732,7 +1731,7 @@ logger('sender: ' . print_r($sender,true)); ); $abook = (($ab) ? $ab[0] : null); - if($arr['item_restrict'] & ITEM_DELETED) { + if(intval($arr['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']); @@ -1757,17 +1756,19 @@ logger('sender: ' . print_r($sender,true)); continue; } - $r = q("select id, edited, item_restrict, item_flags, mid, parent_mid from item where mid = '%s' and uid = %d limit 1", + $r = q("select * from item where mid = '%s' and uid = %d limit 1", dbesc($arr['mid']), intval($channel['channel_id']) ); if($r) { // We already have this post. $item_id = $r[0]['id']; - if($r[0]['item_restrict'] & ITEM_DELETED) { - // It was deleted locally. + + if(intval($r[0]['item_deleted'])) { + // It was deleted locally. $DR->update('update ignored'); $result[] = $DR->get(); + continue; } // Maybe it has been edited? @@ -1779,7 +1780,7 @@ logger('sender: ' . print_r($sender,true)); $result[] = $DR->get(); } else { - update_imported_item($sender,$arr,$channel['channel_id']); + update_imported_item($sender,$arr,$r[0],$channel['channel_id']); $DR->update('updated'); $result[] = $DR->get(); if(! $relay) @@ -1790,9 +1791,10 @@ logger('sender: ' . print_r($sender,true)); $DR->update('update ignored'); $result[] = $DR->get(); - // We need this line to ensure wall-to-wall comments are relayed (by falling through to the relay bit), - // and at the same time not relay any other relayable posts more than once, because to do so is very wasteful. - if(! ($r[0]['item_flags'] & ITEM_ORIGIN)) + + // We need this line to ensure wall-to-wall comments are relayed (by falling through to the relay bit), + // and at the same time not relay any other relayable posts more than once, because to do so is very wasteful. + if(! intval($r[0]['item_origin'])) continue; } } @@ -1921,9 +1923,20 @@ function remove_community_tag($sender, $arr, $uid) { * @param array $item * @param int $uid (unused) */ -function update_imported_item($sender, $item, $uid) { +function update_imported_item($sender, $item, $orig, $uid) { + $x = item_store_update($item); + + // If we're updating an event that we've saved locally, we store the item info first + // because event_addtocal will parse the body to get the 'new' event details + + if($orig['resource_type'] === 'event') { + $res = event_addtocal($orig['id'],$uid); + if(! $res) + logger('update event: failed'); + } + if(! $x['item_id']) logger('update_imported_item: failed: ' . $x['message']); else @@ -1948,7 +1961,12 @@ function delete_imported_item($sender, $item, $uid, $relay) { $item_found = false; $post_id = 0; - $r = q("select id, item_restrict, author_xchan, owner_xchan, source_xchan from item where mid = '%s' and uid = %d limit 1", + + $r = q("select id, item_deleted from item where ( author_xchan = '%s' or owner_xchan = '%s' or source_xchan = '%s' ) + and mid = '%s' and uid = %d limit 1", + dbesc($sender['hash']), + dbesc($sender['hash']), + dbesc($sender['hash']), dbesc($item['mid']), intval($uid) ); @@ -1980,8 +1998,10 @@ function delete_imported_item($sender, $item, $uid, $relay) { return false; } + require_once('include/items.php'); + if ($item_found) { - if ($r[0]['item_restrict'] & ITEM_DELETED) { + if (intval($r[0]['item_deleted'])) { logger('delete_imported_item: item was already deleted'); if (! $relay) return false; @@ -1993,9 +2013,8 @@ function delete_imported_item($sender, $item, $uid, $relay) { // back, and we aren't going to (or shouldn't at any rate) delete it again in the future - so losing // this information from the metadata should have no other discernible impact. - if (($r[0]['id'] != $r[0]['parent']) && ($r[0]['item_flags'] & ITEM_ORIGIN)) { - q("update item set item_flags = %d where id = %d and uid = %d", - intval($r[0]['item_flags'] ^ ITEM_ORIGIN), + if (($r[0]['id'] != $r[0]['parent']) && intval($r[0]['item_origin'])) { + q("update item set item_origin = 0 where id = %d and uid = %d", intval($r[0]['id']), intval($r[0]['uid']) ); @@ -2046,7 +2065,7 @@ function process_mail_delivery($sender, $arr, $deliveries) { intval($channel['channel_id']) ); if($r) { - if($arr['mail_flags'] & MAIL_RECALLED) { + if(intval($arr['mail_recalled'])) { $x = q("delete from mail where id = %d and channel_id = %d", intval($r[0]['id']), intval($channel['channel_id']) @@ -2256,23 +2275,16 @@ function sync_locations($sender, $arr, $absolute = false) { $current_site = true; } - // If it is the site we're currently talking to, and it's marked offline, - // either we have some bad information - or the thing came back to life. - - if(($current_site) && ($r[0]['hubloc_status'] & HUBLOC_OFFLINE)) { - q("update hubloc set hubloc_status = (hubloc_status & ~%d) where hubloc_id = %d", - intval(HUBLOC_OFFLINE), + if($current_site && intval($r[0]['hubloc_error'])) { + q("update hubloc set hubloc_error = 0 where hubloc_id = %d", intval($r[0]['hubloc_id']) ); - if($r[0]['hubloc_flags'] & HUBLOC_FLAGS_ORPHANCHECK) { - q("update hubloc set hubloc_flags = (hubloc_flags & ~%d) where hubloc_id = %d", - intval(HUBLOC_FLAGS_ORPHANCHECK), + if(intval($r[0]['hubloc_orphancheck'])) { + q("update hubloc set hubloc_orphancheck = 0 where hubloc_id = %d", intval($r[0]['hubloc_id']) ); } - q("update xchan set xchan_flags = (xchan_flags & ~%d) where (xchan_flags & %d)>0 and xchan_hash = '%s'", - intval(XCHAN_FLAGS_ORPHAN), - intval(XCHAN_FLAGS_ORPHAN), + q("update xchan set xchan_orphan = 0 where xchan_orphan = 1 and xchan_hash = '%s'", dbesc($sender['hash']) ); } @@ -2288,25 +2300,23 @@ function sync_locations($sender, $arr, $absolute = false) { } } - if(($r[0]['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY) && (! $location['primary'])) { - $m = q("update hubloc set hubloc_flags = (hubloc_flags & ~%d), hubloc_updated = '%s' where hubloc_id = %d", - intval(HUBLOC_FLAGS_PRIMARY), + if(intval($r[0]['hubloc_primary']) && (! $location['primary'])) { + $m = q("update hubloc set hubloc_primary = 0, hubloc_updated = '%s' where hubloc_id = %d", dbesc(datetime_convert()), intval($r[0]['hubloc_id']) ); - $r[0]['hubloc_flags'] = $r[0]['hubloc_flags'] ^ HUBLOC_FLAGS_PRIMARY; + $r[0]['hubloc_primary'] = intval($location['primary']); hubloc_change_primary($r[0]); $what .= 'primary_hub '; $changed = true; } - elseif((! ($r[0]['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY)) && ($location['primary'])) { - $m = q("update hubloc set hubloc_flags = (hubloc_flags | %d), hubloc_updated = '%s' where hubloc_id = %d", - intval(HUBLOC_FLAGS_PRIMARY), + elseif((! intval($r[0]['hubloc_primary'])) && ($location['primary'])) { + $m = q("update hubloc set hubloc_primary = 1, hubloc_updated = '%s' where hubloc_id = %d", dbesc(datetime_convert()), intval($r[0]['hubloc_id']) ); // make sure hubloc_change_primary() has current data - $r[0]['hubloc_flags'] = $r[0]['hubloc_flags'] ^ HUBLOC_FLAGS_PRIMARY; + $r[0]['hubloc_primary'] = intval($location['primary']); hubloc_change_primary($r[0]); $what .= 'primary_hub '; $changed = true; @@ -2315,22 +2325,21 @@ function sync_locations($sender, $arr, $absolute = false) { // Absolute sync - make sure the current primary is correctly reflected in the xchan $pr = hubloc_change_primary($r[0]); if($pr) { - $what .= 'xchan_primary'; + $what .= 'xchan_primary '; $changed = true; } } - if(($r[0]['hubloc_flags'] & HUBLOC_FLAGS_DELETED) && (! $location['deleted'])) { - $n = q("update hubloc set hubloc_flags = (hubloc_flags & ~%d), hubloc_updated = '%s' where hubloc_id = %d", - intval(HUBLOC_FLAGS_DELETED), + if((intval($r[0]['hubloc_deleted']) && (! $location['deleted'])) + || ((! (intval($r[0]['hubloc_deleted']))) && ($location['deleted']))) { + $n = q("update hubloc set hubloc_deleted = 0, hubloc_updated = '%s' where hubloc_id = %d", dbesc(datetime_convert()), intval($r[0]['hubloc_id']) ); $what .= 'delete_hub '; $changed = true; } - elseif((! ($r[0]['hubloc_flags'] & HUBLOC_FLAGS_DELETED)) && ($location['deleted'])) { - $n = q("update hubloc set hubloc_flags = (hubloc_flags | %d), hubloc_updated = '%s' where hubloc_id = %d", - intval(HUBLOC_FLAGS_DELETED), + elseif((! intval($r[0]['hubloc_deleted'])) && ($location['deleted'])) { + $n = q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id = %d", dbesc(datetime_convert()), intval($r[0]['hubloc_id']) ); @@ -2344,22 +2353,20 @@ function sync_locations($sender, $arr, $absolute = false) { // New hub claiming to be primary. Make it so by removing any existing primaries. if(intval($location['primary'])) { - $r = q("update hubloc set hubloc_flags = (hubloc_flags & ~%d), hubloc_updated = '%s' where hubloc_hash = '%s' and (hubloc_flags & %d )>0", - intval(HUBLOC_FLAGS_PRIMARY), + $r = q("update hubloc set hubloc_primary = 0, hubloc_updated = '%s' where hubloc_hash = '%s' and hubloc_primary = 1", dbesc(datetime_convert()), - dbesc($sender['hash']), - intval(HUBLOC_FLAGS_PRIMARY) + dbesc($sender['hash']) ); } logger('sync_locations: new hub: ' . $location['url']); - $r = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_network, hubloc_flags, hubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey, hubloc_updated, hubloc_connected) + $r = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_network, hubloc_primary, hubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey, hubloc_updated, hubloc_connected) values ( '%s','%s','%s','%s', '%s', %d ,'%s','%s','%s','%s','%s','%s','%s')", dbesc($sender['guid']), dbesc($sender['guid_sig']), dbesc($sender['hash']), dbesc($location['address']), dbesc('zot'), - intval((intval($location['primary'])) ? HUBLOC_FLAGS_PRIMARY : 0), + intval($location['primary']), dbesc($location['url']), dbesc($location['url_sig']), dbesc($location['host']), @@ -2387,8 +2394,7 @@ function sync_locations($sender, $arr, $absolute = false) { foreach($xisting as $x) { if(! array_key_exists('updated',$x)) { logger('sync_locations: deleting unreferenced hub location ' . $x['hubloc_url']); - $r = q("update hubloc set hubloc_flags = (hubloc_flags | %d), hubloc_updated = '%s' where hubloc_id = %d", - intval(HUBLOC_FLAGS_DELETED), + $r = q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id = %d", dbesc(datetime_convert()), intval($x['hubloc_id']) ); @@ -2398,6 +2404,9 @@ function sync_locations($sender, $arr, $absolute = false) { } } } + else { + logger('No locations to sync!'); + } $ret['change_message'] = $what; $ret['changed'] = $changed; @@ -2417,20 +2426,19 @@ function zot_encode_locations($channel) { $ret = array(); $x = zot_get_hublocs($channel['channel_hash']); - if ($x && count($x)) { - foreach ($x as $hub) { - if (! ($hub['hubloc_flags'] & HUBLOC_FLAGS_UNVERIFIED)) { - $ret[] = array( - 'host' => $hub['hubloc_host'], - 'address' => $hub['hubloc_addr'], - 'primary' => (($hub['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY) ? true : false), - 'url' => $hub['hubloc_url'], - 'url_sig' => $hub['hubloc_url_sig'], - 'callback' => $hub['hubloc_callback'], - 'sitekey' => $hub['hubloc_sitekey'], - 'deleted' => (($hub['hubloc_flags'] & HUBLOC_FLAGS_DELETED) ? true : false) - ); - } + + if($x && count($x)) { + foreach($x as $hub) { + $ret[] = array( + 'host' => $hub['hubloc_host'], + 'address' => $hub['hubloc_addr'], + 'primary' => (intval($hub['hubloc_primary']) ? true : false), + 'url' => $hub['hubloc_url'], + 'url_sig' => $hub['hubloc_url_sig'], + 'callback' => $hub['hubloc_callback'], + 'sitekey' => $hub['hubloc_sitekey'], + 'deleted' => (intval($hub['hubloc_deleted']) ? true : false) + ); } } @@ -2486,9 +2494,8 @@ function import_directory_profile($hash, $profile, $addr, $ud_flags = UPDATE_FLA // These are not translated, so the German "erwachsenen" keyword will not censor the directory profile. Only the English form - "adult". - if (in_arrayi('nsfw', $clean) || in_arrayi('adult', $clean)) { - q("update xchan set xchan_flags = (xchan_flags | %d) where xchan_hash = '%s'", - intval(XCHAN_FLAGS_SELFCENSORED), + if(in_arrayi('nsfw',$clean) || in_arrayi('adult',$clean)) { + q("update xchan set xchan_selfcensored = 1 where xchan_hash = '%s'", dbesc($hash) ); } @@ -2748,7 +2755,7 @@ function import_site($arr, $pubkey) { // logger('import_site: input: ' . print_r($arr,true)); // logger('import_site: stored: ' . print_r($siterecord,true)); - $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', site_realm = '%s' + $r = q("update site set site_dead = 0, site_location = '%s', site_flags = %d, site_access = %d, site_directory = '%s', site_register = %d, site_update = '%s', site_sellpage = '%s', site_realm = '%s', site_type = %d where site_url = '%s'", dbesc($site_location), intval($site_directory), @@ -2758,6 +2765,7 @@ function import_site($arr, $pubkey) { dbesc(datetime_convert()), dbesc($sellpage), dbesc($site_realm), + intval(SITE_TYPE_ZOT), dbesc($url) ); if(! $r) { @@ -2766,7 +2774,7 @@ function import_site($arr, $pubkey) { } else { // update the timestamp to indicate we communicated with this site - q("update site set site_update = '%s' where site_url = '%s'", + q("update site set site_dead = 0, site_update = '%s' where site_url = '%s'", dbesc(datetime_convert()), dbesc($url) ); @@ -2774,8 +2782,8 @@ function import_site($arr, $pubkey) { } else { $update = true; - $r = q("insert into site ( site_location, site_url, site_access, site_flags, site_update, site_directory, site_register, site_sellpage, site_realm ) - values ( '%s', '%s', %d, %d, '%s', '%s', %d, '%s', '%s' )", + $r = q("insert into site ( site_location, site_url, site_access, site_flags, site_update, site_directory, site_register, site_sellpage, site_realm, site_type ) + values ( '%s', '%s', %d, %d, '%s', '%s', %d, '%s', '%s', %d )", dbesc($site_location), dbesc($url), intval($access_policy), @@ -2784,7 +2792,8 @@ function import_site($arr, $pubkey) { dbesc($directory_url), intval($register_policy), dbesc($sellpage), - dbesc($site_realm) + dbesc($site_realm), + intval(SITE_TYPE_ZOT) ); if(! $r) { logger('import_site: record create failed. ' . print_r($arr,true)); @@ -2826,13 +2835,11 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) { $channel = $r[0]; - if(intval($channel['channel_pageflags']) & PAGE_REMOVED) + if(intval($channel['channel_removed'])) return; - $h = q("select * from hubloc where hubloc_hash = '%s' and not (hubloc_flags & %d) > 0 and not (hubloc_status & %d) > 0", - dbesc($channel['channel_hash']), - intval(HUBLOC_FLAGS_DELETED), - intval(HUBLOC_OFFLINE) + $h = q("select * from hubloc where hubloc_hash = '%s' and hubloc_deleted = 0", + dbesc($channel['channel_hash']) ); if(! $h) @@ -2881,10 +2888,7 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) { // don't pass these elements, they should not be synchronised - if(($k === 'channel_pageflags') && ($v & PAGE_SYSTEM)) - $v = (string) intval($v - PAGE_SYSTEM); - - $disallowed = array('channel_id','channel_account_id','channel_primary','channel_prvkey','channel_address'); + $disallowed = array('channel_id','channel_account_id','channel_primary','channel_prvkey','channel_address','channel_deleted','channel_removed','channel_system'); if(in_array($k,$disallowed)) continue; @@ -2944,6 +2948,8 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) { */ function process_channel_sync_delivery($sender, $arr, $deliveries) { + require_once('include/import.php'); + /** @FIXME this will sync red structures (channel, pconfig and abook). Eventually we need to make this application agnostic. */ $result = array(); @@ -2976,17 +2982,49 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { } } + if(array_key_exists('obj',$arr) && $arr['obj']) + sync_objs($channel,$arr['obj']); + + if(array_key_exists('likes',$arr) && $arr['likes']) + import_likes($channel,$arr['likes']); + + if(array_key_exists('app',$arr) && $arr['app']) + sync_apps($channel,$arr['app']); + + if(array_key_exists('chatroom',$arr) && $arr['chatroom']) + sync_chatrooms($channel,$arr['chatroom']); + + if(array_key_exists('event',$arr) && $arr['event']) + sync_events($channel,$arr['event']); + + if(array_key_exists('event_item',$arr) && $arr['event_item']) + sync_items($channel,$arr['event_item']); + + if(array_key_exists('item',$arr) && $arr['item']) + sync_items($channel,$arr['item']); + + if(array_key_exists('item_id',$arr) && $arr['item_id']) + sync_items($channel,$arr['item_id']); + + if(array_key_exists('menu',$arr) && $arr['menu']) + sync_menus($channel,$arr['menu']); + if(array_key_exists('channel',$arr) && is_array($arr['channel']) && count($arr['channel'])) { - // These flags cannot be sync'd. - // If these bits aren't set locally, remove the bits from the incoming flags. + if(array_key_exists('channel_pageflags',$arr['channel']) && intval($arr['channel']['channel_pageflags'])) { + // These flags cannot be sync'd. + // remove the bits from the incoming flags. + + // These correspond to PAGE_REMOVED and PAGE_SYSTEM on redmatrix - if((! ($channel['channel_pageflags'] & PAGE_REMOVED)) && ($arr['channel']['channel_pageflags'] & PAGE_REMOVED)) - $arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] - PAGE_REMOVED; - if((! ($channel['channel_pageflags'] & PAGE_SYSTEM)) && ($arr['channel']['channel_pageflags'] & PAGE_SYSTEM)) - $arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] - PAGE_SYSTEM; + if($arr['channel']['channel_pageflags'] & 0x8000) + $arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] - 0x8000; + if($arr['channel']['channel_pageflags'] & 0x1000) + $arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] - 0x1000; - $disallowed = array('channel_id','channel_account_id','channel_primary','channel_prvkey', 'channel_address', 'channel_notifyflags', 'channel_removed', 'channel_system', 'channel_deleted' ); + } + + $disallowed = array('channel_id','channel_account_id','channel_primary','channel_prvkey', 'channel_address', 'channel_notifyflags', 'channel_removed', 'channel_deleted', 'channel_system'); $clean = array(); foreach($arr['channel'] as $k => $v) { @@ -3006,43 +3044,32 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { $total_friends = 0; $total_feeds = 0; - $r = q("select abook_id, abook_flags from abook where abook_channel = %d", + $r = q("select abook_id, abook_feed from abook where abook_channel = %d", intval($channel['channel_id']) ); if($r) { // don't count yourself $total_friends = ((count($r) > 0) ? count($r) - 1 : 0); foreach($r as $rr) - if($rr['abook_flags'] & ABOOK_FLAG_FEED) + if(intval($rr['abook_feed'])) $total_feeds ++; } - $disallowed = array('abook_id','abook_account','abook_channel','abook_blocked','abook_ignored','abook_hidden','abook_archived','abook_pending','abook_unconnected','abook_self','abook_feed'); - foreach($arr['abook'] as $abook) { + $disallowed = array('abook_id','abook_account','abook_channel','abook_rating','abook_rating_text'); - if(array_key_exists('abook_blocked',$abook)) { - - // convert from hubzilla - - $abook['abook_flags'] = 0; - if(intval($abook['abook_blocked'])) - $abook['abook_flags'] |= ABOOK_FLAG_BLOCKED; - if(intval($abook['abook_ignored'])) - $abook['abook_flags'] |= ABOOK_FLAG_IGNORED; - if(intval($abook['abook_hidden'])) - $abook['abook_flags'] |= ABOOK_FLAG_HIDDEN; - if(intval($abook['abook_archived'])) - $abook['abook_flags'] |= ABOOK_FLAG_ARCHIVED; - if(intval($abook['abook_pending'])) - $abook['abook_flags'] |= ABOOK_FLAG_PENDING; - if(intval($abook['abook_unconnected'])) - $abook['abook_flags'] |= ABOOK_FLAG_UNCONNECTED; - if(intval($abook['abook_self'])) - $abook['abook_flags'] |= ABOOK_FLAG_SELF; - if(intval($abook['abook_feed'])) - $abook['abook_flags'] |= ABOOK_FLAG_FEED; + foreach($arr['abook'] as $abook) { + if(! array_key_exists('abook_blocked',$abook)) { + // convert from redmatrix + $abook['abook_blocked'] = (($abook['abook_flags'] & 0x0001) ? 1 : 0); + $abook['abook_ignored'] = (($abook['abook_flags'] & 0x0002) ? 1 : 0); + $abook['abook_hidden'] = (($abook['abook_flags'] & 0x0004) ? 1 : 0); + $abook['abook_archived'] = (($abook['abook_flags'] & 0x0008) ? 1 : 0); + $abook['abook_pending'] = (($abook['abook_flags'] & 0x0010) ? 1 : 0); + $abook['abook_unconnected'] = (($abook['abook_flags'] & 0x0020) ? 1 : 0); + $abook['abook_self'] = (($abook['abook_flags'] & 0x0080) ? 1 : 0); + $abook['abook_feed'] = (($abook['abook_flags'] & 0x0100) ? 1 : 0); } $clean = array(); @@ -3050,16 +3077,15 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { logger('process_channel_sync_delivery: removing abook entry for ' . $abook['abook_xchan']); require_once('include/Contact.php'); - $r = q("select abook_id, abook_flags from abook where abook_xchan = '%s' and abook_channel = %d and not ( abook_flags & %d )>0 limit 1", + $r = q("select abook_id, abook_feed from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1", dbesc($abook['abook_xchan']), - intval($channel['channel_id']), - intval(ABOOK_FLAG_SELF) + intval($channel['channel_id']) ); if($r) { contact_remove($channel['channel_id'],$r[0]['abook_id']); if($total_friends) $total_friends --; - if($r[0]['abook_flags'] & ABOOK_FLAG_FEED) + if(intval($r[0]['abook_feed'])) $total_feeds --; } continue; @@ -3101,7 +3127,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { logger('process_channel_sync_delivery: total_channels service class limit exceeded'); continue; } - if($max_feeds !== false && ($clean['abook_flags'] & ABOOK_FLAG_FEED) && $total_feeds > $max_feeds) { + if($max_feeds !== false && intval($clean['abook_feed']) && $total_feeds > $max_feeds) { logger('process_channel_sync_delivery: total_feeds service class limit exceeded'); continue; } @@ -3110,7 +3136,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { intval($channel['channel_id']) ); $total_friends ++; - if($clean['abook_flags'] & ABOOK_FLAG_FEED) + if(intval($clean['abook_feed'])) $total_feeds ++; } @@ -3122,6 +3148,9 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { . "' where abook_xchan = '" . dbesc($clean['abook_xchan']) . "' and abook_channel = " . intval($channel['channel_id'])); } } + + + } } @@ -3314,6 +3343,8 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { if(array_key_exists('item_id',$arr) && $arr['item_id']) sync_items($channel,$arr['item_id']); + $addon = array('channel' => $channel,'data' => $arr); + call_hooks('process_channel_sync_delivery',$addon); // we should probably do this for all items, but usually we only send one. @@ -3358,11 +3389,11 @@ function get_rpost_path($observer) { * @return boolean|string return false or a hash */ function import_author_zot($x) { - $hash = make_xchan_hash($x['guid'], $x['guid_sig']); - $r = q("select hubloc_url from hubloc where hubloc_guid = '%s' and hubloc_guid_sig = '%s' and (hubloc_flags & %d)>0 limit 1", + + $hash = make_xchan_hash($x['guid'],$x['guid_sig']); + $r = q("select hubloc_url from hubloc where hubloc_guid = '%s' and hubloc_guid_sig = '%s' and hubloc_primary = 1 limit 1", dbesc($x['guid']), - dbesc($x['guid_sig']), - intval(HUBLOC_FLAGS_PRIMARY) + dbesc($x['guid_sig']) ); if ($r) { @@ -3432,12 +3463,9 @@ function zot_process_message_request($data) { if ($messages) { $env_recips = null; - $r = q("select hubloc_guid, hubloc_url, hubloc_sitekey, hubloc_network, hubloc_flags, hubloc_callback, hubloc_host - from hubloc where hubloc_hash = '%s' and not (hubloc_flags & %d)>0 - and not (hubloc_status & %d)>0 ", - dbesc($sender_hash), - intval(HUBLOC_FLAGS_DELETED), - intval(HUBLOC_OFFLINE) + $r = q("select * from hubloc where hubloc_hash = '%s' and not hubloc_error and not hubloc_deleted + group by hubloc_sitekey", + dbesc($sender_hash) ); if (! $r) { logger('no hubs'); @@ -3487,77 +3515,355 @@ function zot_process_message_request($data) { } +function zotinfo($arr) { -function import_items($channel,$items) { + $ret = array('success' => false); - if($channel && $items) { - $allow_code = false; - $r = q("select account_id, account_roles, channel_pageflags from account left join channel on channel_account_id = account_id - where channel_id = %d limit 1", - intval($channel['channel_id']) - ); - if($r) { - if(($r[0]['account_roles'] & ACCOUNT_ROLE_ALLOWCODE) || ($r[0]['channel_pageflags'] & PAGE_ALLOWCODE)) { - $allow_code = true; - } + $zhash = ((x($arr,'guid_hash')) ? $arr['guid_hash'] : ''); + $zguid = ((x($arr,'guid')) ? $arr['guid'] : ''); + $zguid_sig = ((x($arr,'guid_sig')) ? $arr['guid_sig'] : ''); + $zaddr = ((x($arr,'address')) ? $arr['address'] : ''); + $ztarget = ((x($arr,'target')) ? $arr['target'] : ''); + $zsig = ((x($arr,'target_sig')) ? $arr['target_sig'] : ''); + $zkey = ((x($arr,'key')) ? $arr['key'] : ''); + $mindate = ((x($arr,'mindate')) ? $arr['mindate'] : ''); + $feed = ((x($arr,'feed')) ? intval($arr['feed']) : 0); + + if($ztarget) { + if((! $zkey) || (! $zsig) || (! rsa_verify($ztarget,base64url_decode($zsig),$zkey))) { + logger('zfinger: invalid target signature'); + $ret['message'] = t("invalid target signature"); + return($ret); } + } - foreach($items as $i) { - $item = get_item_elements($i,$allow_code); - if(! $item) - continue; + $r = null; - $r = q("select id, edited from item where mid = '%s' and uid = %d limit 1", - dbesc($item['mid']), - intval($channel['channel_id']) + if(strlen($zhash)) { + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where channel_hash = '%s' limit 1", + dbesc($zhash) + ); + } + elseif(strlen($zguid) && strlen($zguid_sig)) { + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where channel_guid = '%s' and channel_guid_sig = '%s' limit 1", + dbesc($zguid), + dbesc($zguid_sig) + ); + } + elseif(strlen($zaddr)) { + if(strpos($zaddr,'[system]') === false) { /* normal address lookup */ + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where ( channel_address = '%s' or xchan_addr = '%s' ) limit 1", + dbesc($zaddr), + dbesc($zaddr) ); - if($r) { - if($item['edited'] > $r[0]['edited']) { - $item['id'] = $r[0]['id']; - $item['uid'] = $channel['channel_id']; - item_store_update($item); - continue; - } + } + + else { + + /** + * The special address '[system]' will return a system channel if one has been defined, + * Or the first valid channel we find if there are no system channels. + * + * This is used by magic-auth if we have no prior communications with this site - and + * returns an identity on this site which we can use to create a valid hub record so that + * we can exchange signed messages. The precise identity is irrelevant. It's the hub + * information that we really need at the other end - and this will return it. + * + */ + + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where channel_system = 1 order by channel_id limit 1"); + if(! $r) { + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where channel_removed = 0 order by channel_id limit 1"); } - else { - $item['aid'] = $channel['channel_account_id']; - $item['uid'] = $channel['channel_id']; - $item_result = item_store($item); + } + } + else { + $ret['message'] = 'Invalid request'; + return($ret); + } + + if(! $r) { + $ret['message'] = 'Item not found.'; + return($ret); + } + + $e = $r[0]; + + $id = $e['channel_id']; + + $sys_channel = (intval($e['channel_system']) ? true : false); + $special_channel = (($e['channel_pageflags'] & PAGE_PREMIUM) ? true : false); + $adult_channel = (($e['channel_pageflags'] & PAGE_ADULT) ? true : false); + $censored = (($e['channel_pageflags'] & PAGE_CENSORED) ? true : false); + $searchable = (($e['channel_pageflags'] & PAGE_HIDDEN) ? false : true); + $deleted = (intval($e['xchan_deleted']) ? true : false); + + if($deleted || $censored || $sys_channel) + $searchable = false; + + $public_forum = false; + + $role = get_pconfig($e['channel_id'],'system','permissions_role'); + if($role === 'forum' || $role === 'repository') { + $public_forum = true; + } + else { + // check if it has characteristics of a public forum based on custom permissions. + $t = q("select abook_my_perms from abook where abook_channel = %d and abook_self = 1 limit 1", + intval($e['channel_id']) + ); + if(($t) && (($t[0]['abook_my_perms'] & PERMS_W_TAGWALL) && (! ($t[0]['abook_my_perms'] & PERMS_W_STREAM)))) + $public_forum = true; + } + + + // This is for birthdays and keywords, but must check access permissions + $p = q("select * from profile where uid = %d and is_default = 1", + intval($e['channel_id']) + ); + + $profile = array(); + + if($p) { + + if(! intval($p[0]['publish'])) + $searchable = false; + + $profile['description'] = $p[0]['pdesc']; + $profile['birthday'] = $p[0]['dob']; + if(($profile['birthday'] != '0000-00-00') && (($bd = z_birthday($p[0]['dob'],$e['channel_timezone'])) !== '')) + $profile['next_birthday'] = $bd; + + if($age = age($p[0]['dob'],$e['channel_timezone'],'')) + $profile['age'] = $age; + $profile['gender'] = $p[0]['gender']; + $profile['marital'] = $p[0]['marital']; + $profile['sexual'] = $p[0]['sexual']; + $profile['locale'] = $p[0]['locality']; + $profile['region'] = $p[0]['region']; + $profile['postcode'] = $p[0]['postal_code']; + $profile['country'] = $p[0]['country_name']; + $profile['about'] = $p[0]['about']; + $profile['homepage'] = $p[0]['homepage']; + $profile['hometown'] = $p[0]['hometown']; + + if($p[0]['keywords']) { + $tags = array(); + $k = explode(' ',$p[0]['keywords']); + if($k) { + foreach($k as $kk) { + if(trim($kk," \t\n\r\0\x0B,")) { + $tags[] = trim($kk," \t\n\r\0\x0B,"); + } + } } + if($tags) + $profile['keywords'] = $tags; + } + } + + $ret['success'] = true; + + // Communication details + + $ret['guid'] = $e['xchan_guid']; + $ret['guid_sig'] = $e['xchan_guid_sig']; + $ret['key'] = $e['xchan_pubkey']; + $ret['name'] = $e['xchan_name']; + $ret['name_updated'] = $e['xchan_name_date']; + $ret['address'] = $e['xchan_addr']; + $ret['photo_mimetype'] = $e['xchan_photo_mimetype']; + $ret['photo'] = $e['xchan_photo_l']; + $ret['photo_updated'] = $e['xchan_photo_date']; + $ret['url'] = $e['xchan_url']; + $ret['connections_url']= (($e['xchan_connurl']) ? $e['xchan_connurl'] : z_root() . '/poco/' . $e['channel_address']); + $ret['target'] = $ztarget; + $ret['target_sig'] = $zsig; + $ret['searchable'] = $searchable; + $ret['adult_content'] = $adult_channel; + $ret['public_forum'] = $public_forum; + if($deleted) + $ret['deleted'] = $deleted; + + // premium or other channel desiring some contact with potential followers before connecting. + // This is a template - %s will be replaced with the follow_url we discover for the return channel. + + if($special_channel) + $ret['connect_url'] = z_root() . '/connect/' . $e['channel_address']; + + // This is a template for our follow url, %s will be replaced with a webbie + + $ret['follow_url'] = z_root() . '/follow?f=&url=%s'; + + $ztarget_hash = (($ztarget && $zsig) + ? make_xchan_hash($ztarget,$zsig) + : '' ); + + $permissions = get_all_perms($e['channel_id'],$ztarget_hash,false); + + if($ztarget_hash) { + $permissions['connected'] = false; + $b = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", + dbesc($ztarget_hash), + intval($e['channel_id']) + ); + if($b) + $permissions['connected'] = true; + } + + $ret['permissions'] = (($ztarget && $zkey) ? crypto_encapsulate(json_encode($permissions),$zkey) : $permissions); + + if($permissions['view_profile']) + $ret['profile'] = $profile; + + // array of (verified) hubs this channel uses + + $x = zot_encode_locations($e); + if($x) + $ret['locations'] = $x; + $ret['site'] = array(); + $ret['site']['url'] = z_root(); + $ret['site']['url_sig'] = base64url_encode(rsa_sign(z_root(),$e['channel_prvkey'])); + + $dirmode = get_config('system','directory_mode'); + if(($dirmode === false) || ($dirmode == DIRECTORY_MODE_NORMAL)) + $ret['site']['directory_mode'] = 'normal'; + + if($dirmode == DIRECTORY_MODE_PRIMARY) + $ret['site']['directory_mode'] = 'primary'; + elseif($dirmode == DIRECTORY_MODE_SECONDARY) + $ret['site']['directory_mode'] = 'secondary'; + elseif($dirmode == DIRECTORY_MODE_STANDALONE) + $ret['site']['directory_mode'] = 'standalone'; + if($dirmode != DIRECTORY_MODE_NORMAL) + $ret['site']['directory_url'] = z_root() . '/dirsearch'; + + + // hide detailed site information if you're off the grid + + if($dirmode != DIRECTORY_MODE_STANDALONE) { + + $register_policy = intval(get_config('system','register_policy')); + + if($register_policy == REGISTER_CLOSED) + $ret['site']['register_policy'] = 'closed'; + if($register_policy == REGISTER_APPROVE) + $ret['site']['register_policy'] = 'approve'; + if($register_policy == REGISTER_OPEN) + $ret['site']['register_policy'] = 'open'; + + + $access_policy = intval(get_config('system','access_policy')); + + if($access_policy == ACCESS_PRIVATE) + $ret['site']['access_policy'] = 'private'; + if($access_policy == ACCESS_PAID) + $ret['site']['access_policy'] = 'paid'; + if($access_policy == ACCESS_FREE) + $ret['site']['access_policy'] = 'free'; + if($access_policy == ACCESS_TIERED) + $ret['site']['access_policy'] = 'tiered'; + + $ret['site']['accounts'] = account_total(); + + require_once('include/identity.php'); + $ret['site']['channels'] = channel_total(); + + + $ret['site']['version'] = PLATFORM_NAME . ' ' . RED_VERSION . '[' . DB_UPDATE_VERSION . ']'; + + $ret['site']['admin'] = get_config('system','admin_email'); + + $a = get_app(); + + $visible_plugins = array(); + if(is_array($a->plugins) && count($a->plugins)) { + $r = q("select * from addon where hidden = 0"); + if($r) + foreach($r as $rr) + $visible_plugins[] = $rr['name']; } + + $ret['site']['plugins'] = $visible_plugins; + $ret['site']['sitehash'] = get_config('system','location_hash'); + $ret['site']['sitename'] = get_config('system','sitename'); + $ret['site']['sellpage'] = get_config('system','sellpage'); + $ret['site']['location'] = get_config('system','site_location'); + $ret['site']['realm'] = get_directory_realm(); + } -} + check_zotinfo($e,$x,$ret); + + + call_hooks('zot_finger',$ret); + return($ret); -function sync_items($channel,$items) { - import_items($channel,$items); } +function check_zotinfo($channel,$locations,&$ret) { -function import_item_ids($channel,$itemids) { - if($channel && $itemids) { - foreach($itemids as $i) { - $r = q("select id from item where mid = '%s' and uid = %d limit 1", - dbesc($i['mid']), - intval($channel['channel_id']) + +// logger('locations: ' . print_r($locations,true),LOGGER_DATA); + + // This function will likely expand as we find more things to detect and fix. + // 1. Because magic-auth is reliant on it, ensure that the system channel has a valid hubloc + // Force this to be the case if anything is found to be wrong with it. + + // @FIXME ensure that the system channel exists in the first place and has an xchan + + if($channel['channel_system']) { + // the sys channel must have a location (hubloc) + $valid_location = false; + if((count($locations) === 1) && ($locations[0]['primary']) && (! $locations[0]['deleted'])) { + if((rsa_verify($locations[0]['url'],base64url_decode($locations[0]['url_sig']),$channel['channel_pubkey'])) + && ($locations[0]['sitekey'] === get_config('system','pubkey')) + && ($locations[0]['url'] === z_root())) + $valid_location = true; + else + logger('sys channel: invalid url signature'); + } + + if((! $locations) || (! $valid_location)) { + + logger('System channel locations are not valid. Attempting repair.'); + + // Don't trust any existing records. Just get rid of them, but only do this + // for the sys channel as normal channels will be trickier. + + q("delete from hubloc where hubloc_hash = '%s'", + dbesc($channel['channel_hash']) ); - if(! $r) - continue; - $z = q("select * from item_id where service = '%s' and sid = '%s' and iid = %d and uid = %d limit 1", - dbesc($i['service']), - dbesc($i['sid']), - intval($r[0]['id']), - intval($channel['channel_id']) + $r = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_primary, + hubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey, hubloc_network ) + values ( '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s' )", + dbesc($channel['channel_guid']), + dbesc($channel['channel_guid_sig']), + dbesc($channel['channel_hash']), + dbesc($channel['channel_address'] . '@' . get_app()->get_hostname()), + intval(1), + dbesc(z_root()), + dbesc(base64url_encode(rsa_sign(z_root(),$channel['channel_prvkey']))), + dbesc(get_app()->get_hostname()), + dbesc(z_root() . '/post'), + dbesc(get_config('system','pubkey')), + dbesc('zot') ); - if(! $z) { - q("insert into item_id (iid,uid,sid,service) values(%d,%d,'%s','%s')", - intval($r[0]['id']), - intval($channel['channel_id']), - dbesc($i['sid']), - dbesc($i['service']) - ); + if($r) { + $x = zot_encode_locations($channel); + if($x) { + $ret['locations'] = $x; + } + } + else { + logger('Unable to store sys hub location'); } } } |