function diaspora_post_local(&$a, &$item) { /** * If all the conditions are met, generate an instance of the Diaspora Comment Virus * * Previously all comments from any Hubzilla source (including those who have not opted in to * Diaspora federation), were required to locally generate a Diaspora comment signature. * The only exception was wall-to-wall posts which have no local signing authority. * * Going forward, if we are asked to propagate the virus and it is not present (due to the post author * not opting in to Diaspora federation); we will generate a "wall-to-wall" comment and not require * a source signature. This allows hubs and communities to opt-out of Diaspora federation and not be * forced to generate the comment virus regardless. This is necessary because Diaspora now requires * the virus not just to provide a stored signature and Diaspora formatted text body, but must also * include all XML fields presented by the Diaspora protocol when transmitting the comment, while * maintaining their source order. This is fine for federated communities using UNO, but it makes * no sense to require this low-level baggage in channels and communities that have chosen not to use * the Diaspora protocol and services. * */ require_once 'include/bb2diaspora.php'; if ($item['mid'] === $item['parent_mid']) { return; } if ($item['created'] != $item['edited']) { return; } $meta = null; $author = channelx_by_hash($item['author_xchan']); if ($author) { // The author has a local channel, If they have this connector installed, // sign the comment and create a Diaspora Comment Virus. $dspr_allowed = get_pconfig($author['channel_id'], 'system', 'diaspora_allowed'); if (!$dspr_allowed) { return; } $handle = channel_reddress($author); if ($item['verb'] === ACTIVITY_LIKE) { if ($item['thr_parent'] == $item['parent_mid'] && $item['obj_type'] == ACTIVITY_OBJ_NOTE) { $meta = ['positive' => 'true', 'guid' => $item['mid'], 'target_type' => 'Post', 'parent_guid' => $item['parent_mid'], 'diaspora_handle' => $handle]; } } else { $body = bb2diaspora_itembody($item, true, true); $meta = ['guid' => $item['mid'], 'parent_guid' => $item['parent_mid'], 'text' => $body, 'diaspora_handle' => $handle]; } $meta['author_signature'] = diaspora_sign_fields($meta, $author['channel_prvkey']); if ($item['author_xchan'] === $item['owner_xchan']) { $meta['parent_author_signature'] = diaspora_sign_fields($meta, $author['channel_prvkey']); } } if (!$meta && $item['author_xchan'] !== $item['owner_xchan']) { // A local comment arrived but the commenter does not have a local channel // or the commenter doesn't have the Diaspora plugin enabled. // The owner *should* have a local channel // Find the owner and if the owner has this addon installed, turn the comment into // a 'wall-to-wall' message containing the author attribution, // with the comment signed by the owner. $owner = channelx_by_hash($item['owner_xchan']); if (!$owner) { return; } $dspr_allowed = get_pconfig($owner['channel_id'], 'system', 'diaspora_allowed'); if (!$dspr_allowed) { return; } $handle = channel_reddress($owner); if ($item['verb'] === ACTIVITY_LIKE) { if ($item['thr_parent'] == $item['parent_mid'] && $item['obj_type'] == ACTIVITY_OBJ_NOTE) { $meta = ['positive' => 'true', 'guid' => $item['mid'], 'target_type' => 'Post', 'parent_guid' => $item['parent_mid'], 'diaspora_handle' => $handle]; } } else { $body = bb2diaspora_itembody($item, true, false); $meta = ['guid' => $item['mid'], 'parent_guid' => $item['parent_mid'], 'text' => $body, 'diaspora_handle' => $handle]; } $meta['author_signature'] = diaspora_sign_fields($meta, $owner['channel_prvkey']); $meta['parent_author_signature'] = diaspora_sign_fields($meta, $owner['channel_prvkey']); } if ($meta) { set_iconfig($item, 'diaspora', 'fields', $meta, true); } // otherwise, neither the author or owner have this plugin installed. Do nothing. // logger('ditem: ' . print_r($item,true)); }
function diaspora_like($importer, $xml, $msg) { $a = get_app(); $guid = notags(unxmlify($xml['guid'])); $parent_guid = notags(unxmlify($xml['parent_guid'])); $diaspora_handle = notags(diaspora_get_author($xml)); $target_type = notags(diaspora_get_ptype($xml)); $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 $x = diaspora_verify_fields($xml, $parent_author_signature, $key); if (!$x) { logger('diaspora_like: top-level owner verification failed.'); return; } //$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'] $x = diaspora_verify_fields($xml, $author_signature, $key); if (!$x) { logger('diaspora_like: author verification failed.'); return; } //$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; // } //} $xml['parent_author_signature'] = diaspora_sign_fields($xml, $importer['channel_prvkey']); } 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['obj'] = $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($x); } set_iconfig($arr, 'diaspora', 'fields', array_map('unxmlify', $xml), true); $result = item_store($arr); if ($result['success']) { // 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 (intval($parent_item['item_origin']) && !$parent_author_signature) { Zotlabs\Daemon\Master::Summon(array('Notifier', 'comment-import', $result['item_id'])); } sync_an_item($importer['channel_id'], $result['item_id']); } return; }
function item_store_update($arr, $allow_exec = false, $deliver = true) { $d = array('item' => $arr, 'allow_exec' => $allow_exec); call_hooks('item_store_update', $d); $arr = $d['item']; $allow_exec = $d['allow_exec']; $ret = array('success' => false, 'item_id' => 0); if (!intval($arr['uid'])) { logger('item_store_update: no uid'); $ret['message'] = 'no uid.'; return $ret; } if (!intval($arr['id'])) { logger('item_store_update: no id'); $ret['message'] = 'no id.'; return $ret; } $orig_post_id = $arr['id']; $uid = $arr['uid']; $orig = q("select * from item where id = %d and uid = %d limit 1", intval($orig_post_id), intval($uid)); if (!$orig) { logger('item_store_update: original post not found: ' . $orig_post_id); $ret['message'] = 'no original'; return $ret; } // override the unseen flag with the original $arr['item_unseen'] = $orig[0]['item_unseen']; if (array_key_exists('edit', $arr)) { unset($arr['edit']); } $arr['mimetype'] = x($arr, 'mimetype') ? notags(trim($arr['mimetype'])) : 'text/bbcode'; if ($arr['mimetype'] == 'application/x-php' && !$allow_exec) { logger('item_store: php mimetype but allow_exec is denied.'); $ret['message'] = 'exec denied.'; return $ret; } 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 = 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'); if (is_array($allowed_languages) && $arr['lang'] && !array_key_exists($arr['lang'], $allowed_languages)) { $translate = array('item' => $arr, 'from' => $arr['lang'], 'to' => $allowed_languages, 'translated' => false); call_hooks('item_translate', $translate); if (!$translate['translated'] && intval(get_pconfig($arr['uid'], 'system', 'reject_disallowed_languages'))) { logger('item_store: language ' . $arr['lang'] . ' not accepted for uid ' . $arr['uid']); $ret['message'] = 'language not accepted'; return $ret; } $arr = $translate['item']; } } if (x($arr, 'obj') && is_array($arr['obj'])) { activity_sanitise($arr['obj']); $arr['obj'] = json_encode($arr['obj']); } if (x($arr, 'target') && is_array($arr['target'])) { activity_sanitise($arr['target']); $arr['target'] = json_encode($arr['target']); } if (x($arr, 'attach') && is_array($arr['attach'])) { activity_sanitise($arr['attach']); $arr['attach'] = json_encode($arr['attach']); } unset($arr['id']); unset($arr['uid']); unset($arr['aid']); unset($arr['mid']); unset($arr['parent']); unset($arr['parent_mid']); unset($arr['created']); unset($arr['author_xchan']); unset($arr['owner_xchan']); unset($arr['thr_parent']); unset($arr['llink']); $arr['edited'] = x($arr, 'edited') !== false ? datetime_convert('UTC', 'UTC', $arr['edited']) : datetime_convert(); $arr['expires'] = x($arr, 'expires') !== false ? datetime_convert('UTC', 'UTC', $arr['expires']) : $orig[0]['expires']; if (array_key_exists('comments_closed', $arr) && $arr['comments_closed'] > NULL_DATE) { $arr['comments_closed'] = datetime_convert('UTC', 'UTC', $arr['comments_closed']); } else { $arr['comments_closed'] = $orig[0]['comments_closed']; } $arr['commented'] = $orig[0]['commented']; if ($deliver) { $arr['received'] = datetime_convert(); $arr['changed'] = datetime_convert(); } else { // When deliver flag is false, we are *probably* performing an import or bulk migration. // If one updates the changed timestamp it will be made available to zotfeed and delivery // will still take place through backdoor methods. Since these fields are rarely used // otherwise, just preserve the original timestamp. $arr['received'] = $orig[0]['received']; $arr['changed'] = $orig[0]['changed']; } $arr['route'] = array_key_exists('route', $arr) ? trim($arr['route']) : $orig[0]['route']; $arr['diaspora_meta'] = x($arr, 'diaspora_meta') ? $arr['diaspora_meta'] : $orig[0]['diaspora_meta']; $arr['location'] = x($arr, 'location') ? notags(trim($arr['location'])) : $orig[0]['location']; $arr['coord'] = x($arr, 'coord') ? notags(trim($arr['coord'])) : $orig[0]['coord']; $arr['verb'] = x($arr, 'verb') ? notags(trim($arr['verb'])) : $orig[0]['verb']; $arr['obj_type'] = x($arr, 'obj_type') ? notags(trim($arr['obj_type'])) : $orig[0]['obj_type']; $arr['obj'] = x($arr, 'obj') ? trim($arr['obj']) : $orig[0]['obj']; $arr['tgt_type'] = x($arr, 'tgt_type') ? notags(trim($arr['tgt_type'])) : $orig[0]['tgt_type']; $arr['target'] = x($arr, 'target') ? trim($arr['target']) : $orig[0]['target']; $arr['plink'] = x($arr, 'plink') ? notags(trim($arr['plink'])) : $orig[0]['plink']; $arr['allow_cid'] = array_key_exists('allow_cid', $arr) ? trim($arr['allow_cid']) : $orig[0]['allow_cid']; $arr['allow_gid'] = array_key_exists('allow_gid', $arr) ? trim($arr['allow_gid']) : $orig[0]['allow_gid']; $arr['deny_cid'] = array_key_exists('deny_cid', $arr) ? trim($arr['deny_cid']) : $orig[0]['deny_cid']; $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) && 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['sig'] = x($arr, 'sig') ? $arr['sig'] : ''; $arr['layout_mid'] = array_key_exists('layout_mid', $arr) ? dbesc($arr['layout_mid']) : $orig[0]['layout_mid']; $arr['public_policy'] = x($arr, 'public_policy') ? notags(trim($arr['public_policy'])) : $orig[0]['public_policy']; $arr['comment_policy'] = x($arr, 'comment_policy') ? notags(trim($arr['comment_policy'])) : $orig[0]['comment_policy']; call_hooks('post_remote_update', $arr); if (x($arr, 'cancel')) { logger('item_store_update: post cancelled by plugin.'); $ret['message'] = 'cancelled.'; return $ret; } // pull out all the taxonomy stuff for separate storage $terms = null; if (array_key_exists('term', $arr)) { $terms = $arr['term']; unset($arr['term']); } $meta = null; if (array_key_exists('iconfig', $arr)) { $meta = $arr['iconfig']; unset($arr['iconfig']); } dbesc_array($arr); logger('item_store_update: ' . print_r($arr, true), LOGGER_DATA); $str = ''; foreach ($arr as $k => $v) { if ($str) { $str .= ","; } $str .= " `" . $k . "` = '" . $v . "' "; } $r = dbq("update `item` set " . $str . " where id = " . $orig_post_id); if ($r) { logger('item_store_update: updated item ' . $orig_post_id, LOGGER_DEBUG); } else { logger('item_store_update: could not update item'); $ret['message'] = 'DB update failed.'; return $ret; } // fetch an unescaped complete copy of the stored item $r = q("select * from item where id = %d", intval($orig_post_id)); if ($r) { $arr = $r[0]; } $r = q("delete from term where oid = %d and otype = %d", intval($orig_post_id), intval(TERM_OBJ_POST)); if (is_array($terms)) { foreach ($terms as $t) { q("insert into term (uid,oid,otype,ttype,term,url)\n\t\t\t\tvalues(%d,%d,%d,%d,'%s','%s') ", intval($uid), intval($orig_post_id), intval(TERM_OBJ_POST), intval($t['ttype']), dbesc($t['term']), dbesc($t['url'])); } $arr['term'] = $terms; } $r = q("delete from iconfig where iid = %d", intval($orig_post_id)); if ($meta) { foreach ($meta as $m) { set_iconfig($orig_post_id, $m['cat'], $m['k'], $m['v'], $m['sharing']); } $arr['iconfig'] = $meta; } $ret['item'] = $arr; call_hooks('post_remote_update_end', $arr); if ($deliver) { send_status_notifications($orig_post_id, $arr); tag_deliver($uid, $orig_post_id); } $ret['success'] = true; $ret['item_id'] = $orig_post_id; return $ret; }
function wiki_create_wiki($channel, $observer_hash, $wiki, $acl) { $wikiinit = wiki_init_wiki($channel, $wiki); if (!$wikiinit['path']) { notice('Error creating wiki'); return array('item' => null, 'success' => false); } $path = $wikiinit['path']; // Generate unique resource_id using the same method as item_message_id() do { $dups = false; $resource_id = random_string(); $r = q("SELECT mid FROM item WHERE resource_id = '%s' AND resource_type = '%s' AND uid = %d LIMIT 1", dbesc($resource_id), dbesc(WIKI_ITEM_RESOURCE_TYPE), intval($channel['channel_id'])); if (count($r)) { $dups = true; } } while ($dups == true); $ac = $acl->get(); $mid = item_message_id(); $arr = array(); // Initialize the array of parameters for the post $item_hidden = 0; // TODO: Allow form creator to send post to ACL about new game automatically $wiki_url = z_root() . '/wiki/' . $channel['channel_address'] . '/' . $wiki['urlName']; $arr['aid'] = $channel['channel_account_id']; $arr['uid'] = $channel['channel_id']; $arr['mid'] = $mid; $arr['parent_mid'] = $mid; $arr['item_hidden'] = $item_hidden; $arr['resource_type'] = WIKI_ITEM_RESOURCE_TYPE; $arr['resource_id'] = $resource_id; $arr['owner_xchan'] = $channel['channel_hash']; $arr['author_xchan'] = $observer_hash; $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid']; $arr['llink'] = $arr['plink']; $arr['title'] = $wiki['htmlName']; // name of new wiki; $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['item_wall'] = 1; $arr['item_origin'] = 1; $arr['item_thread_top'] = 1; $arr['item_private'] = intval($acl->is_private()); $arr['verb'] = ACTIVITY_CREATE; $arr['obj_type'] = ACTIVITY_OBJ_WIKI; $arr['body'] = '[table][tr][td][h1]New Wiki[/h1][/td][/tr][tr][td][zrl=' . $wiki_url . ']' . $wiki['htmlName'] . '[/zrl][/td][/tr][/table]'; // Save the path using iconfig. The file path should not be shared with other hubs if (!set_iconfig($arr, 'wiki', 'path', $path, false)) { return array('item' => null, 'success' => false); } // Save the wiki name information using iconfig. This is shareable. if (!set_iconfig($arr, 'wiki', 'rawName', $wiki['rawName'], true)) { return array('item' => null, 'success' => false); } if (!set_iconfig($arr, 'wiki', 'htmlName', $wiki['htmlName'], true)) { return array('item' => null, 'success' => false); } if (!set_iconfig($arr, 'wiki', 'urlName', $wiki['urlName'], true)) { return array('item' => null, 'success' => false); } $post = item_store($arr); $item_id = $post['item_id']; if ($item_id) { proc_run('php', "include/notifier.php", "activity", $item_id); return array('item' => $arr, 'success' => true); } else { return array('item' => null, 'success' => false); } }