]> git.mxchange.org Git - friendica.git/blobdiff - include/items.php
Merge pull request #317 from CatoTH/master
[friendica.git] / include / items.php
index 0a8bc12c0893911e9e414acfb1d993949f8861b3..3fe977b6f77fb9230ef6a42c5dbda0866ca0b347 100644 (file)
@@ -119,7 +119,7 @@ function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0)
        $check_date = datetime_convert('UTC','UTC',$last_update,'Y-m-d H:i:s');
 
        $r = q("SELECT `item`.*, `item`.`id` AS `item_id`, 
-               `contact`.`name`, `contact`.`photo`, `contact`.`url`, 
+               `contact`.`name`, `contact`.`network`, `contact`.`photo`, `contact`.`url`, 
                `contact`.`name-date`, `contact`.`uri-date`, `contact`.`avatar-date`,
                `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, 
                `contact`.`id` AS `contact-id`, `contact`.`uid` AS `contact-uid`,
@@ -952,13 +952,15 @@ function tag_deliver($uid,$item_id) {
 
        $mention = false;
 
-       $u = q("select uid, nickname, language, username, email, `page-flags`, `notify-flags` from user where uid = %d limit 1",
+       $u = q("select * from user where uid = %d limit 1",
                intval($uid)
        );
        if(! count($u))
                return;
 
        $community_page = (($u[0]['page-flags'] == PAGE_COMMUNITY) ? true : false);
+       $prvgroup = (($u[0]['page-flags'] == PAGE_PRVGROUP) ? true : false);
+
 
        $i = q("select * from item where id = %d and uid = %d limit 1",
                intval($item_id),
@@ -1008,9 +1010,10 @@ function tag_deliver($uid,$item_id) {
                'otype'        => 'item'
        ));
 
-       if(! $community_page)
+       if((! $community_page) && (! $prvgroup))
                return;
 
+
        // tgroup delivery - setup a second delivery chain
        // prevent delivery looping - only proceed
        // if the message originated elsewhere and is a top-level post
@@ -1027,10 +1030,23 @@ function tag_deliver($uid,$item_id) {
        if(! count($c))
                return;
 
-       q("update item set wall = 1, origin = 1, forum_mode = 1, `owner-name` = '%s', `owner-link` = '%s', `owner-avatar` = '%s'  where id = %d limit 1",
+       // also reset all the privacy bits to the forum default permissions
+
+       $private = ($u[0]['allow_cid'] || $u[0]['allow_gid'] || $u[0]['deny_cid'] || $u[0]['deny_gid']) ? 1 : 0;
+
+       $forum_mode = (($prvgroup) ? 2 : 1);
+
+       q("update item set wall = 1, origin = 1, forum_mode = %d, `owner-name` = '%s', `owner-link` = '%s', `owner-avatar` = '%s', 
+               `private` = %d, `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s'  where id = %d limit 1",
+               intval($forum_mode),
                dbesc($c[0]['name']),
                dbesc($c[0]['url']),
                dbesc($c[0]['thumb']),
+               intval($private),
+               dbesc($u[0]['allow_cid']),
+               dbesc($u[0]['allow_gid']),
+               dbesc($u[0]['deny_cid']),
+               dbesc($u[0]['deny_gid']),
                intval($item_id)
        );
 
@@ -2184,7 +2200,7 @@ function local_delivery($importer,$data) {
                if($is_reply) {
                        $community = false;
 
-                       if($importer['page-flags'] == PAGE_COMMUNITY) {
+                       if($importer['page-flags'] == PAGE_COMMUNITY || $importer['page-flags'] == PAGE_PRVGROUP ) {
                                $sql_extra = '';
                                $community = true;
                                logger('local_delivery: possible community reply');
@@ -2211,8 +2227,8 @@ function local_delivery($importer,$data) {
                        if($r && count($r))
                                $is_a_remote_comment = true;                    
 
-                       // Does this have the characteristics of a community comment?
-                       // If it's a reply to a wall post on a community page it's a 
+                       // Does this have the characteristics of a community or private group comment?
+                       // If it's a reply to a wall post on a community/prvgroup page it's a 
                        // valid community comment. Also forum_mode makes it valid for sure. 
                        // If neither, it's not.
 
@@ -2227,10 +2243,10 @@ function local_delivery($importer,$data) {
                                logger('local_delivery: received remote comment');
                                $is_like = false;
                                // remote reply to our post. Import and then notify everybody else.
-                               $datarray = get_atom_elements($feed,$item);
 
+                               $datarray = get_atom_elements($feed,$item);
 
-                               $r = q("SELECT `id`, `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
+                               $r = q("SELECT `id`, `uid`, `last-child`, `edited`, `body`  FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
                                        dbesc($item_id),
                                        intval($importer['importer_uid'])
                                );
@@ -2266,14 +2282,22 @@ function local_delivery($importer,$data) {
 //                                     return 0;
 //                             }                                       
 
+                               // our user with $importer['importer_uid'] is the owner
+
+                               $own = q("select name,url,thumb from contact where uid = %d and self = 1 limit 1",
+                                       intval($importer['importer_uid'])
+                               );
+
+
                                $datarray['type'] = 'remote-comment';
                                $datarray['wall'] = 1;
                                $datarray['parent-uri'] = $parent_uri;
                                $datarray['uid'] = $importer['importer_uid'];
-                               $datarray['owner-name'] = $r[0]['name'];
-                               $datarray['owner-link'] = $r[0]['url'];
-                               $datarray['owner-avatar'] = $r[0]['thumb'];
+                               $datarray['owner-name'] = $own[0]['name'];
+                               $datarray['owner-link'] = $own[0]['url'];
+                               $datarray['owner-avatar'] = $own[0]['thumb'];
                                $datarray['contact-id'] = $importer['id'];
+
                                if(($datarray['verb'] === ACTIVITY_LIKE) || ($datarray['verb'] === ACTIVITY_DISLIKE)) {
                                        $is_like = true;
                                        $datarray['type'] = 'activity';
@@ -2290,26 +2314,34 @@ function local_delivery($importer,$data) {
                                }
 
                                if(($datarray['verb'] === ACTIVITY_TAG) && ($datarray['object-type'] === ACTIVITY_OBJ_TAGTERM)) {
-
-
+                                       
                                        $xo = parse_xml_string($datarray['object'],false);
                                        $xt = parse_xml_string($datarray['target'],false);
 
-                                       if(($xt->type == ACTIVITY_OBJ_NOTE) && ($xt->id == $r[0]['uri'])) {
+                                       if(($xt->type == ACTIVITY_OBJ_NOTE) && ($xt->id)) {
+
+                                               // fetch the parent item
+
+                                               $tagp = q("select * from item where uri = '%s' and uid = %d limit 1",
+                                                       dbesc($xt->id),
+                                                       intval($importer['importer_uid'])
+                                               );
+                                               if(! count($tagp))
+                                                       continue;       
 
                                                // extract tag, if not duplicate, and this user allows tags, add to parent item                                         
 
                                                if($xo->id && $xo->content) {
                                                        $newtag = '#[url=' . $xo->id . ']'. $xo->content . '[/url]';
-
-                                                       if(! (stristr($r[0]['tag'],$newtag))) {
+                                                       if(! (stristr($tagp[0]['tag'],$newtag))) {
                                                                $i = q("SELECT `blocktags` FROM `user` where `uid` = %d LIMIT 1",
                                                                        intval($importer['importer_uid'])
                                                                );
-                                                               if(count($i) && ! ($i[0]['blocktags'])) {
-                                                                       q("UPDATE item SET tag = '%s' WHERE id = %d LIMIT 1",
-                                                                               dbesc($r[0]['tag'] . (strlen($r[0]['tag']) ? ',' : '') . $newtag),
-                                                                               intval($r[0]['id'])
+                                                               if(count($i) && ! intval($i[0]['blocktags'])) {
+                                                                       q("UPDATE item SET tag = '%s', `edited` = '%s' WHERE id = %d LIMIT 1",
+                                                                               dbesc($tagp[0]['tag'] . (strlen($tagp[0]['tag']) ? ',' : '') . $newtag),
+                                                                               intval($tagp[0]['id']),
+                                                                               dbesc(datetime_convert())
                                                                        );
                                                                }
                                                        }
@@ -2479,7 +2511,7 @@ function local_delivery($importer,$data) {
                        
                                if(!x($datarray['type']) || $datarray['type'] != 'activity') {
 
-                                       $myconv = q("SELECT `author-link`, `author-avatar`, `parent` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `parent` != 0 ",
+                                       $myconv = q("SELECT `author-link`, `author-avatar`, `parent` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `parent` != 0 AND `deleted` = 0",
                                                dbesc($parent_uri),
                                                intval($importer['importer_uid'])
                                        );
@@ -2685,6 +2717,12 @@ function new_follower($importer,$contact,$datarray,$item,$sharing = false) {
                );
                $a = get_app();
                if(count($r)) {
+
+                       if(intval($r[0]['def_gid'])) {
+                               require_once('include/group.php');
+                               group_add_member($r[0]['uid'],'',$contact_record['id'],$r[0]['def_gid']);
+                       }
+
                        if(($r[0]['notify-flags'] & NOTIFY_INTRO) && ($r[0]['page-flags'] == PAGE_NORMAL)) {
                                $email_tpl = get_intltext_template('follow_notify_eml.tpl');
                                $email = replace_macros($email_tpl, array(
@@ -2794,7 +2832,7 @@ function atom_author($tag,$name,$uri,$h,$w,$photo) {
        return $o;
 }
 
-function atom_entry($item,$type,$author,$owner,$comment = false) {
+function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) {
 
        $a = get_app();
 
@@ -2806,7 +2844,7 @@ function atom_entry($item,$type,$author,$owner,$comment = false) {
 
 
        if($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid'])
-               $body = fix_private_photos($item['body'],$owner['uid']);
+               $body = fix_private_photos($item['body'],$owner['uid'],$item,$cid);
        else
                $body = $item['body'];
 
@@ -2889,14 +2927,17 @@ function atom_entry($item,$type,$author,$owner,$comment = false) {
        return $o;
 }
 
-function fix_private_photos($s,$uid) {
+function fix_private_photos($s,$uid, $item = null, $cid = 0) {
        $a = get_app();
-       logger('fix_private_photos');
+
+       logger('fix_private_photos', LOGGER_DEBUG);
+       $site = substr($a->get_baseurl(),strpos($a->get_baseurl,'://'));
 
        if(preg_match("/\[img\](.*?)\[\/img\]/is",$s,$matches)) {
                $image = $matches[1];
-               logger('fix_private_photos: found photo ' . $image);
-               if(stristr($image ,$a->get_baseurl() . '/photo/')) {
+               logger('fix_private_photos: found photo ' . $image, LOGGER_DEBUG);
+               if(stristr($image , $site . '/photo/')) {
+                       $replace = false;
                        $i = basename($image);
                        $i = str_replace('.jpg','',$i);
                        $x = strpos($i,'-');
@@ -2909,17 +2950,86 @@ function fix_private_photos($s,$uid) {
                                        intval($uid)
                                );
                                if(count($r)) {
-                                       logger('replacing photo');
-                                       $s = str_replace($image, 'data:image/jpg;base64,' . base64_encode($r[0]['data']), $s);
+
+                                       // Check to see if we should replace this photo link with an embedded image
+                                       // 1. No need to do so if the photo is public
+                                       // 2. If there's a contact-id provided, see if they're in the access list
+                                       //    for the photo. If so, embed it. 
+                                       // 3. Otherwise, if we have an item, see if the item permissions match the photo
+                                       //    permissions, regardless of order but first check to see if they're an exact
+                                       //    match to save some processing overhead.
+                               
+                                       // Currently we only embed one private photo per message so as not to hit import 
+                                       // size limits at the receiving end.
+
+                                       // To embed multiples, we would need to parse out the embedded photos on message
+                                       // receipt and limit size based only on the text component. Would also need to
+                                       // ignore all photos during bbcode translation and item localisation, as these
+                                       // will hit internal regex backtrace limits.  
+
+                                       if(has_permissions($r[0])) {
+                                               if($cid) {
+                                                       $recips = enumerate_permissions($r[0]);
+                                                       if(in_array($cid, $recips)) {
+                                                               $replace = true;        
+                                                       }
+                                               }
+                                               elseif($item) {
+                                                       if(compare_permissions($item,$r[0]))
+                                                               $replace = true;
+                                               }
+                                       }
+                                       if($replace) {
+                                               logger('fix_private_photos: replacing photo', LOGGER_DEBUG);
+                                               $s = str_replace($image, 'data:image/jpg;base64,' . base64_encode($r[0]['data']), $s);
+                                               logger('fix_private_photos: replaced: ' . $s, LOGGER_DATA);
+                                       }
                                }
                        }
-                       logger('fix_private_photos: replaced: ' . $s, LOGGER_DATA);
                }       
        }
        return($s);
 }
 
 
+function has_permissions($obj) {
+       if(($obj['allow_cid'] != '') || ($obj['allow_gid'] != '') || ($obj['deny_cid'] != '') || ($obj['deny_gid'] != ''))
+               return true;
+       return false;
+}
+
+function compare_permissions($obj1,$obj2) {
+       // first part is easy. Check that these are exactly the same. 
+       if(($obj1['allow_cid'] == $obj2['allow_cid'])
+               && ($obj1['allow_gid'] == $obj2['allow_gid'])
+               && ($obj1['deny_cid'] == $obj2['deny_cid'])
+               && ($obj1['deny_gid'] == $obj2['deny_gid']))
+               return true;
+
+       // This is harder. Parse all the permissions and compare the resulting set.
+
+       $recipients1 = enumerate_permissions($obj1);
+       $recipients2 = enumerate_permissions($obj2);
+       sort($recipients1);
+       sort($recipients2);
+       if($recipients1 == $recipients2)
+               return true;
+       return false;
+}
+
+// returns an array of contact-ids that are allowed to see this object
+
+function enumerate_permissions($obj) {
+       require_once('include/group.php');
+       $allow_people = expand_acl($obj['allow_cid']);
+       $allow_groups = expand_groups(expand_acl($obj['allow_gid']));
+       $deny_people  = expand_acl($obj['deny_cid']);
+       $deny_groups  = expand_groups(expand_acl($obj['deny_gid']));
+       $recipients   = array_unique(array_merge($allow_people,$allow_groups));
+       $deny         = array_unique(array_merge($deny_people,$deny_groups));
+       $recipients   = array_diff($recipients,$deny);
+       return $recipients;
+}
 
 function item_getfeedtags($item) {
        $ret = array();
@@ -2966,13 +3076,20 @@ function item_getfeedattach($item) {
        
 function item_expire($uid,$days) {
 
-       if((! $uid) || (! $days))
+       if((! $uid) || ($days < 1))
                return;
 
+       // $expire_network_only = save your own wall posts
+       // and just expire conversations started by others
+
+       $expire_network_only = get_pconfig($uid,'expire','network_only');
+       $sql_extra = ((intval($expire_network_only)) ? " AND wall = 0 " : "");
+
        $r = q("SELECT * FROM `item` 
                WHERE `uid` = %d 
                AND `created` < UTC_TIMESTAMP() - INTERVAL %d DAY 
                AND `id` = `parent` 
+               $sql_extra
                AND `deleted` = 0",
                intval($uid),
                intval($days)
@@ -3013,32 +3130,7 @@ function item_expire($uid,$days) {
                if($expire_items==0 && $item['type']!='note')
                        continue;
 
-
-               $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s' WHERE `id` = %d LIMIT 1",
-                       dbesc(datetime_convert()),
-                       dbesc(datetime_convert()),
-                       intval($item['id'])
-               );
-
-               $r = q("DELETE FROM item_id where iid in (select id from item where parent = %d) and uid = %d",
-                       intval($item['id']),
-                       intval($uid)
-               );
-
-               $r = q("DELETE FROM sign where iid in (select id from item where parent = %d) and uid = %d",
-                       intval($item['id']),
-                       intval($uid)
-               );
-
-               // kill the kids
-
-               $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d ",
-                       dbesc(datetime_convert()),
-                       dbesc(datetime_convert()),
-                       dbesc($item['parent-uri']),
-                       intval($item['uid'])
-               );
-
+               drop_item($item['id'],false);
        }
 
        proc_run('php',"include/notifier.php","expire","$uid");
@@ -3100,6 +3192,25 @@ function drop_item($id,$interactive = true) {
                        intval($item['id'])
                );
 
+               // clean up categories and tags so they don't end up as orphans
+
+               $matches = false;
+               $cnt = preg_match_all('/<(.*?)>/',$item['file'],$matches,PREG_SET_ORDER);
+               if($cnt) {
+                       foreach($matches as $mtch) {
+                               file_tag_unsave_file($item['uid'],$item['id'],$mtch[1],true);
+                       }
+               }
+
+               $matches = false;
+
+               $cnt = preg_match_all('/\[(.*?)\]/',$item['file'],$matches,PREG_SET_ORDER);
+               if($cnt) {
+                       foreach($matches as $mtch) {
+                               file_tag_unsave_file($item['uid'],$item['id'],$mtch[1],false);
+                       }
+               }
+
                // If item is a link to a photo resource, nuke all the associated photos 
                // (visitors will not have photo resources)
                // This only applies to photos uploaded from the photos page. Photos inserted into a post do not
@@ -3123,6 +3234,17 @@ function drop_item($id,$interactive = true) {
                        // ignore the result
                }
 
+               // clean up item_id and sign meta-data tables
+
+               $r = q("DELETE FROM item_id where iid in (select id from item where parent = %d and uid = %d)",
+                       intval($item['id']),
+                       intval($item['uid'])
+               );
+
+               $r = q("DELETE FROM sign where iid in (select id from item where parent = %d and uid = %d)",
+                       intval($item['id']),
+                       intval($item['uid'])
+               );
 
                // If it's the parent of a comment thread, kill all the kids
 
@@ -3155,7 +3277,7 @@ function drop_item($id,$interactive = true) {
                        }       
                }
                $drop_id = intval($item['id']);
-                       
+
                // send the notification upstream/downstream as the case may be
 
                if(! $interactive)