diff options
author | Stefan Parviainen <saparvia@caterva.eu> | 2014-11-08 20:53:41 +0100 |
---|---|---|
committer | Stefan Parviainen <saparvia@caterva.eu> | 2014-11-08 20:53:41 +0100 |
commit | b5fad9feefd0f261807222d8a4c42ead6253a65c (patch) | |
tree | 399cd4a1b79f61530924ea59670af0bdd6cee5be /include | |
parent | 89aea081825ec7b11b00833a9bec2c74900bfcb6 (diff) | |
parent | b29a968be8df52cd7c9b6d5bebb618534788337c (diff) | |
download | volse-hubzilla-b5fad9feefd0f261807222d8a4c42ead6253a65c.tar.gz volse-hubzilla-b5fad9feefd0f261807222d8a4c42ead6253a65c.tar.bz2 volse-hubzilla-b5fad9feefd0f261807222d8a4c42ead6253a65c.zip |
Fix merge conflict
Diffstat (limited to 'include')
-rw-r--r-- | include/Contact.php | 21 | ||||
-rw-r--r-- | include/Import/Importer.php | 94 | ||||
-rw-r--r-- | include/Import/refimport.php | 282 | ||||
-rw-r--r-- | include/RedDAV/RedBrowser.php | 1 | ||||
-rw-r--r-- | include/api.php | 12 | ||||
-rw-r--r-- | include/bb2diaspora.php | 35 | ||||
-rw-r--r-- | include/conversation.php | 26 | ||||
-rw-r--r-- | include/deliver.php | 28 | ||||
-rwxr-xr-x | include/diaspora.php | 21 | ||||
-rw-r--r-- | include/event.php | 14 | ||||
-rw-r--r-- | include/follow.php | 13 | ||||
-rw-r--r-- | include/html2bbcode.php | 4 | ||||
-rw-r--r-- | include/hubloc.php | 90 | ||||
-rw-r--r-- | include/identity.php | 24 | ||||
-rwxr-xr-x | include/items.php | 59 | ||||
-rw-r--r-- | include/notifier.php | 34 | ||||
-rw-r--r-- | include/onepoll.php | 21 | ||||
-rw-r--r-- | include/permissions.php | 51 | ||||
-rw-r--r-- | include/photos.php | 4 | ||||
-rw-r--r-- | include/poller.php | 20 | ||||
-rw-r--r-- | include/reddav.php | 4 | ||||
-rw-r--r-- | include/session.php | 5 | ||||
-rw-r--r-- | include/taxonomy.php | 24 | ||||
-rw-r--r-- | include/widgets.php | 43 | ||||
-rw-r--r-- | include/zot.php | 191 |
25 files changed, 990 insertions, 131 deletions
diff --git a/include/Contact.php b/include/Contact.php index 4440369dc..20e5e1a1e 100644 --- a/include/Contact.php +++ b/include/Contact.php @@ -245,11 +245,13 @@ function channel_remove($channel_id, $local = true, $unset_session=true) { intval($channel_id) ); + $r = q("update hubloc set hubloc_flags = (hubloc_flags | %d) where hubloc_hash = '%s'", intval(HUBLOC_FLAGS_DELETED), dbesc($channel['channel_hash']) ); + $r = q("update xchan set xchan_flags = (xchan_flags | %d) where xchan_hash = '%s'", intval(XCHAN_FLAGS_DELETED), dbesc($channel['channel_hash']) @@ -257,7 +259,6 @@ function channel_remove($channel_id, $local = true, $unset_session=true) { proc_run('php','include/notifier.php','purge_all',$channel_id); - } q("DELETE FROM `groups` WHERE `uid` = %d", intval($channel_id)); @@ -291,11 +292,23 @@ function channel_remove($channel_id, $local = true, $unset_session=true) { dbesc(z_root()) ); - $r = q("update xchan set xchan_flags = (xchan_flags | %d) where xchan_hash = '%s' ", - intval(XCHAN_FLAGS_DELETED), - dbesc($channel['channel_hash']) + // Do we have any valid hublocs remaining? + + $hublocs = 0; + + $r = q("select hubloc_id from hubloc where hubloc_hash = '%s' and not (hubloc_flags & %d)", + dbesc($channel['channel_hash']), + intval(HUBLOC_FLAGS_DELETED) ); + 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), + dbesc($channel['channel_hash']) + ); + } proc_run('php','include/directory.php',$channel_id); diff --git a/include/Import/Importer.php b/include/Import/Importer.php new file mode 100644 index 000000000..c42344236 --- /dev/null +++ b/include/Import/Importer.php @@ -0,0 +1,94 @@ +<?php /** @file */ + +namespace Redmatrix\Import; + + +class Import { + + $credentials = null; + $itemlist = null; + $src_items = null; + + $items = null; + + function get_credentials() { + + } + + function get_itemlist() { + + + } + + + function get_item_ident($item) { + + } + + function get_item($item_ident) { + + } + + function get_taxonomy($item_ident) { + + } + + function get_children($item_ident) { + + } + + function convert_item($item_ident) { + + } + + function convert_taxonomy($item_ident) { + + + } + + function convert_child($child) { + + } + + function store($item,$update = false) { + + } + + function run() { + + $this->credentials = $this->get_credentials(); + $this->itemlist = $this->get_itemlist(); + if($this->itemlist) { + $this->src_items = array(); + $this->items = array(); + $cnt = 0; + foreach($this->itemlist as $item) { + $ident = $item->get_item_ident($item); + $this->src_items[$ident]['item'] = $this->get_item($ident); + $this->src_items[$ident]['taxonomy'] = $this->get_taxonomy($ident); + $this->src_items[$ident]['children'] = $this->get_children($ident); + $this->items[$cnt]['item'] = $this->convert_item($ident); + $this->items[$cnt]['item']['term'] = $this->convert_taxonomy($ident); + if($this->src_items[$ident]['children']) { + $this->items[$cnt]['children'] = array(); + foreach($this->src_items[$ident]['children'] as $child) { + $this[$cnt]['children'][] = $this->convert_child($child); + } + } + $cnt ++; + } + + + + + } + + + + + + + } + + +}
\ No newline at end of file diff --git a/include/Import/refimport.php b/include/Import/refimport.php new file mode 100644 index 000000000..4f2572660 --- /dev/null +++ b/include/Import/refimport.php @@ -0,0 +1,282 @@ +<?php + +require_once('include/html2bbcode.php'); +require_once('include/hubloc.php'); + +// Sample module for importing conversation data from Reflection CMS. Some preparation was used to +// dump relevant posts, categories and comments into individual JSON files, and also JSON dump of +// the user table to search for avatars. Importation was also batched in sets of 20 posts per page +// visit so as to survive shared hosting process limits. This provides some clues as how to handle +// WordPress imports, which use a somewhat similar DB structure. The batching and individual files +// might not be needed in VPS environments. As such this could be considered an extreme test case, but +// the importation was successful in all regards using this code. The module URL was visited repeatedly +// with a browser until all the posts had been imported. + + + + +define('REDMATRIX_IMPORTCHANNEL','mike'); +define('REFLECT_EXPORTUSERNAME','mike'); +define('REFLECT_BLOGNAME','Diary and Other Rantings'); +define('REFLECT_BASEURL','http://example.com/'); +define('REFLECT_USERFILE','user.json'); + +// set to true if you need to process everything again +define('REFLECT_OVERWRITE',false); + +// we'll only process a small number of posts at a time on a shared host. + +define('REFLECT_MAXPERRUN',30); + +function reflect_get_channel() { + + // this will be the channel_address or nickname of the red channel + + $c = q("select * from channel left join xchan on channel_hash = xchan_hash + where channel_address = '%s' limit 1", + dbesc(REDMATRIX_IMPORTCHANNEL) + ); + return $c[0]; +} + + +function refimport_content(&$a) { + + $channel = reflect_get_channel(); + + // load the user file. We need that to find the commenter's avatars + + $u = file_get_contents(REFLECT_USERFILE); + if($u) { + $users = json_decode($u,true); + } + + $ignored = 0; + $processed = 0; + + $files = glob('article/*'); + if(! $files) + return; + + foreach($files as $f) { + $s = file_get_contents($f); + $j = json_decode($s,true); + + if(! $j) + continue; + + $arr = array(); + + // see if this article was already processed + $r = q("select * from item where mid = '%s' and uid = %d limit 1", + dbesc($j['guid']), + intval($channel['channel_id']) + ); + if($r) { + if(REFLECT_OVERWRITE) + $arr['id'] = $r[0]['id']; + else { + $ignored ++; + rename($f,str_replace('article','done',$f)); + continue; + } + } + + $arr['uid'] = $channel['channel_account_id']; + $arr['aid'] = $channel['channel_id']; + $arr['mid'] = $arr['parent_mid'] = $j['guid']; + $arr['created'] = $j['created']; + $arr['edited'] = $j['edited']; + $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['verb'] = ACTIVITY_POST; + + // this is an assumption + $arr['comment_policy'] = 'contacts'; + + + // import content. In this case the content is XHTML. + + $arr['title'] = html2bbcode($j['title']); + $arr['title'] = htmlspecialchars($arr['title'],ENT_COMPAT,'UTF-8',false); + + + $arr['body'] = html2bbcode($j['body']); + $arr['body'] = htmlspecialchars($arr['body'],ENT_COMPAT,'UTF-8',false); + + + // convert relative urls to other posts on that service to absolute url on our service. + $arr['body'] = preg_replace_callback("/\[url\=\/+article\/(.*?)\](.*?)\[url\]/",'reflect_article_callback',$arr['body']); + + // also import any photos + $arr['body'] = preg_replace_callback("/\[img(.*?)\](.*?)\[\/img\]/",'reflect_photo_callback',$arr['body']); + + + // add categories + + if($j['taxonomy'] && is_array($j['taxonomy']) && count($j['taxonomy'])) { + $arr['term'] = array(); + foreach($j['taxonomy'] as $tax) { + $arr['term'][] = array( + 'uid' => $channel['channel_id'], + 'type' => TERM_CATEGORY, + 'otype' => TERM_OBJ_POST, + 'term' => trim($tax['name']), + 'url' => $channel['xchan_url'] . '?f=&cat=' . urlencode(trim($tax['name'])) + ); + } + } + + // store the item + + if($arr['id']) + item_store_update($arr); + else + item_store($arr); + + // if there are any comments, process them + // $comment['registered'] is somebody with an account on the system. Others are mostly anonymous + + if($j['comments']) { + foreach($j['comments'] as $comment) { + $user = (($comment['registered']) ? reflect_find_user($users,$comment['author']) : null); + reflect_comment_store($channel,$arr,$comment,$user); + } + } + $processed ++; + + if(REFLECT_MAXPERRUN && $processed > REFLECT_MAXPERRUN) + break; + } + return 'processed: ' . $processed . EOL . 'completed: ' . $ignored . EOL; + +} + +function reflect_article_callback($matches) { + return '[zrl=' . z_root() . '/display/'. $matches[1] . ']' . $matches[2] . '[/zrl]'; +} + +function reflect_photo_callback($matches) { + + if(strpos($matches[2],'http') !== false) + return $matches[0]; + + $prefix = REFLECT_BASEURL; + $x = z_fetch_url($prefix.$matches[2],true); + + $hash = basename($matches[2]); + + if($x['success']) { + $channel = reflect_get_channel(); + require_once('include/photos.php'); + $p = photo_upload($channel,$channel, + array('data' => $x['body'], + 'resource_id' => str_replace('-','',$hash), + 'filename' => $hash . '.jpg', + 'type' => 'image/jpeg', + 'not_visible' => true + ) + ); + + if($p['success']) + $newlink = $p['resource_id'] . '-0.jpg'; + + + // import photo and locate the link for it. + return '[zmg]' . z_root() . '/photo/' . $newlink . '[/zmg]'; + + } + // no replacement. Leave it alone. + return $matches[0]; +} + +function reflect_find_user($users,$name) { + if($users) { + foreach($users as $x) { + if($x['name'] === $name) { + return $x; + } + } + } + + return false; + +} + +function reflect_comment_store($channel,$post,$comment,$user) { + + // if the commenter was the channel owner, use their redmatrix xchan + + if($comment['author'] === REFLECT_EXPORTUSERNAME && $comment['registered']) + $hash = $channel['xchan_hash']; + else { + // we need a unique hash for the commenter. We don't know how many may have supplied + // http://yahoo.com as their URL, so we'll use their avatar guid if they have one. + // anonymous folks may get more than one xchan_hash if they commented more than once. + + $hash = (($comment['registered'] && $user) ? $user['avatar'] : ''); + if(! $hash) + $hash = random_string() . '.unknown'; + + // create an xchan for them which will also import their profile photo + // they will have a network type 'unknown'. + + $x = array( + 'hash' => $hash, + 'guid' => $hash, + 'url' => (($comment['url']) ? $comment['url'] : z_root()), + 'photo' => (($user) ? REFLECT_BASEURL . $user['avatar'] : z_root() . '/' . get_default_profile_photo()), + 'name' => $comment['author'] + ); + xchan_store($x); + + } + + $arr = array(); + + $r = q("select * from item where mid = '%s' and uid = %d limit 1", + dbesc($comment['guid']), + intval($channel['channel_id']) + ); + if($r) { + if(REFLECT_OVERWRITE) + $arr['id'] = $r[0]['id']; + else + return; + } + + // this is a lot like storing the post except for subtle differences, like parent_mid, flags, author_xchan, + // and we don't have a comment edited field so use creation date + + $arr['uid'] = $channel['channel_account_id']; + $arr['aid'] = $channel['channel_id']; + $arr['mid'] = $comment['guid']; + $arr['parent_mid'] = $post['mid']; + $arr['created'] = $comment['created']; + $arr['edited'] = $comment['created']; + $arr['author_xchan'] = $hash; + $arr['owner_xchan'] = $channel['channel_hash']; + $arr['item_flags'] = ITEM_ORIGIN|ITEM_WALL; + $arr['verb'] = ACTIVITY_POST; + $arr['comment_policy'] = 'contacts'; + + + $arr['title'] = html2bbcode($comment['title']); + $arr['title'] = htmlspecialchars($arr['title'],ENT_COMPAT,'UTF-8',false); + + + $arr['body'] = html2bbcode($comment['body']); + $arr['body'] = htmlspecialchars($arr['body'],ENT_COMPAT,'UTF-8',false); + $arr['body'] = preg_replace_callback("/\[url\=\/+article\/(.*?)\](.*?)\[url\]/",'reflect_article_callback',$arr['body']); + $arr['body'] = preg_replace_callback("/\[img(.*?)\](.*?)\[\/img\]/",'reflect_photo_callback',$arr['body']); + + // logger('comment: ' . print_r($arr,true)); + + if($arr['id']) + item_store_update($arr); + else + item_store($arr); + +} diff --git a/include/RedDAV/RedBrowser.php b/include/RedDAV/RedBrowser.php index 6ec5c978d..21ea76aed 100644 --- a/include/RedDAV/RedBrowser.php +++ b/include/RedDAV/RedBrowser.php @@ -259,6 +259,7 @@ class RedBrowser extends DAV\Browser\Plugin { $html .= $output; get_app()->page['content'] = $html; + load_pdl(get_app()); construct_page(get_app()); } diff --git a/include/api.php b/include/api.php index 8b52253dd..9fe2ef47d 100644 --- a/include/api.php +++ b/include/api.php @@ -621,7 +621,19 @@ require_once('include/items.php'); api_register_func('api/red/group','api_group', true); + function api_red_xchan(&$a,$type) { + if(api_user() === false) + return false; + require_once('include/hubloc.php'); + if($_SERVER['request_method'] === 'POST') { + $r = xchan_store($_REQUEST); + } + $r = xchan_fetch($_REQUEST); + json_return_and_die($r); + }; + api_register_func('api/red/xchan','api_red_xchan',true); + function api_statuses_mediap(&$a, $type) { if (api_user() === false) { diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php index 9a87de5b2..3c4f07568 100644 --- a/include/bb2diaspora.php +++ b/include/bb2diaspora.php @@ -116,6 +116,8 @@ function diaspora_mention_callback($matches) { function diaspora2bb($s,$use_zrl = false) { + $s = str_replace("
\n>","",$s); + $s = html_entity_decode($s,ENT_COMPAT,'UTF-8'); // Too many new lines. So deactivated the following line @@ -275,7 +277,7 @@ function bb2diaspora_itemwallwall(&$item) { } if(($item['mid'] == $item['parent_mid']) && ($item['author_xchan'] != $item['owner_xchan']) && (is_array($item['author']))) { - logger('bb2diaspora_itemwallwall: author: ' . print_r($item['author'],true), LOGGER_DEBUG); + logger('bb2diaspora_itemwallwall: author: ' . print_r($item['author'],true), LOGGER_DATA); } if(($item['mid'] == $item['parent_mid']) && ($item['author_xchan'] != $item['owner_xchan']) && (is_array($item['author'])) && $item['author']['xchan_url'] && $item['author']['xchan_name'] && $item['author']['xchan_photo_m']) { @@ -290,14 +292,18 @@ function bb2diaspora_itemwallwall(&$item) { // We have to do something similar for wall-to-wall comments. ITEM_WALL|ITEM_ORIGIN indicates that it was posted on this site. // Regular matrix comments may have one of these bits set, but not both. - if(($item['mid'] != $item['parent_mid']) && ($item['author_xchan'] != $item['owner_xchan']) && ($item['item_flags'] & (ITEM_WALL|ITEM_ORIGIN)) && (is_array($item['author'])) && $item['author']['xchan_url'] && $item['author']['xchan_name'] && $item['author']['xchan_photo_m']) { - logger('bb2diaspora_itemwallwall: wall to wall comment',LOGGER_DEBUG); + // Update: this is getting triggered way too often and unnecessarily. Commenting out until we find a better solution. + // It's not an easy problem. For now we'll live with the mis-attributions, as wall to wall comments are much less frequent + // than wall-to-wall posts. + +// if(($item['mid'] != $item['parent_mid']) && ($item['author_xchan'] != $item['owner_xchan']) && (($item['item_flags'] & (ITEM_WALL|ITEM_ORIGIN)) == (ITEM_WALL|ITEM_ORIGIN)) && (is_array($item['author'])) && $item['author']['xchan_url'] && $item['author']['xchan_name'] && $item['author']['xchan_photo_m']) { +// logger('bb2diaspora_itemwallwall: wall to wall comment',LOGGER_DEBUG); // post will come across with the owner's identity. Throw a preamble onto the post to indicate the true author. - $item['body'] = "\n\n" - . '[img]' . $item['author']['xchan_photo_m'] . '[/img]' - . '[url=' . $item['author']['xchan_url'] . ']' . $item['author']['xchan_name'] . '[/url]' . "\n\n" - . $item['body']; - } +// $item['body'] = "\n\n" +// . '[img]' . $item['author']['xchan_photo_m'] . '[/img]' +// . '[url=' . $item['author']['xchan_url'] . ']' . $item['author']['xchan_name'] . '[/url]' . "\n\n" +// . $item['body']; +// } // $item['author'] might cause a surprise further down the line if it wasn't expected to be here. @@ -334,8 +340,13 @@ function bb2diaspora_itembody($item,$force_update = false) { if(array_key_exists('item_flags',$item) && ($item['item_flags'] & ITEM_OBSCURED)) { $key = get_config('system','prvkey'); - $newitem['title'] = (($item['title']) ? crypto_unencapsulate(json_decode($item['title'],true),$key) : ''); - $newitem['body'] = (($item['body']) ? crypto_unencapsulate(json_decode($item['body'],true),$key) : ''); + $b = json_decode($item['body'],true); + // if called from diaspora_process_outbound, this decoding has already been done. + // Everything else that calls us will not yet be decoded. + if($b && is_array($b) && array_key_exists('iv',$b)) { + $newitem['title'] = (($item['title']) ? crypto_unencapsulate(json_decode($item['title'],true),$key) : ''); + $newitem['body'] = (($item['body']) ? crypto_unencapsulate(json_decode($item['body'],true),$key) : ''); + } } bb2diaspora_itemwallwall($newitem); @@ -377,7 +388,7 @@ function bb2diaspora_itembody($item,$force_update = false) { } } - logger('bb2diaspora_itembody : ' . $body); +// logger('bb2diaspora_itembody : ' . $body, LOGGER_DATA); return html_entity_decode($body); @@ -451,7 +462,7 @@ function format_event_diaspora($ev) { $bd_format = t('l F d, Y \@ g:i A') ; // Friday January 18, 2011 @ 8 AM - $o = 'Friendica event notification:' . "\n"; + $o = t('Redmatrix event notification:') . "\n"; $o .= '**' . (($ev['summary']) ? bb2diaspora($ev['summary']) : bb2diaspora($ev['desc'])) . '**' . "\n"; diff --git a/include/conversation.php b/include/conversation.php index b22b570a1..a531de9ba 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -827,8 +827,8 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ $threads = null; } - if($page_mode === 'preview') - logger('preview: ' . print_r($threads,true)); +// if($page_mode === 'preview') +// logger('preview: ' . print_r($threads,true)); // Do not un-comment if smarty3 is in use // logger('page_template: ' . $page_template); @@ -1551,16 +1551,18 @@ function profile_tabs($a, $is_owner=False, $nickname=Null){ ); } - require_once('include/chat.php'); - $has_chats = chatroom_list_count($uid); - if ($has_chats) { - $tabs[] = array( - 'label' => t('Chatrooms'), - 'url' => $a->get_baseurl() . '/chat/' . $nickname, - 'sel' => ((argv(0) == 'chat') ? 'active' : '' ), - 'title' => t('Chatrooms'), - 'id' => 'chat-tab', - ); + if($p['chat']) { + require_once('include/chat.php'); + $has_chats = chatroom_list_count($uid); + if ($has_chats) { + $tabs[] = array( + 'label' => t('Chatrooms'), + 'url' => $a->get_baseurl() . '/chat/' . $nickname, + 'sel' => ((argv(0) == 'chat') ? 'active' : '' ), + 'title' => t('Chatrooms'), + 'id' => 'chat-tab', + ); + } } require_once('include/menu.php'); diff --git a/include/deliver.php b/include/deliver.php index f4fae6061..729018448 100644 --- a/include/deliver.php +++ b/include/deliver.php @@ -38,15 +38,33 @@ function deliver_run($argv, $argc) { continue; } - if($r[0]['outq_posturl'] === z_root() . '/post') { + $notify = json_decode($r[0]['outq_notify'],true); + + // Check if this is a conversation request packet. It won't have outq_msg + // but will be an encrypted packet - so will need to be handed off to + // web delivery rather than processed inline. + + $sendtoweb = false; + if(array_key_exists('iv',$notify) && (! $r[0]['outq_msg'])) + $sendtoweb = true; + + if(($r[0]['outq_posturl'] === z_root() . '/post') && (! $sendtoweb)) { logger('deliver: local delivery', LOGGER_DEBUG); // local delivery // we should probably batch these and save a few delivery processes - // If there is no outq_msg, this is a refresh_all message which does not require local handling - if($r[0]['outq_msg']) { - $msg = array('body' => json_encode(array('pickup' => array(array('notify' => json_decode($r[0]['outq_notify'],true),'message' => json_decode($r[0]['outq_msg'],true)))))); - zot_import($msg,z_root()); + if($r[0]['outq_msg']) { + $m = json_decode($r[0]['outq_msg'],true); + if(array_key_exists('message_list',$m)) { + foreach($m['message_list'] as $mm) { + $msg = array('body' => json_encode(array('pickup' => array(array('notify' => $notify,'message' => $mm))))); + zot_import($msg,z_root()); + } + } + else { + $msg = array('body' => json_encode(array('pickup' => array(array('notify' => $notify,'message' => $m))))); + zot_import($msg,z_root()); + } $r = q("delete from outq where outq_hash = '%s' limit 1", dbesc($argv[$x]) ); diff --git a/include/diaspora.php b/include/diaspora.php index c6d4b7423..7858fa203 100755 --- a/include/diaspora.php +++ b/include/diaspora.php @@ -58,7 +58,7 @@ function diaspora_dispatch($importer,$msg,$attempt=1) { $xmlbase = $parsed_xml->post; - logger('diaspora_dispatch: ' . print_r($xmlbase,true), LOGGER_DATA); +// logger('diaspora_dispatch: ' . print_r($xmlbase,true), LOGGER_DATA); if($xmlbase->request) { @@ -673,16 +673,15 @@ function diaspora_request($importer,$xml) { return; } - $default_perms = 0; - // look for default permissions to apply in return - e.g. auto-friend - $z = q("select * from abook where abook_channel = %d and (abook_flags & %d) limit 1", - intval($importer['channel_id']), - intval(ABOOK_FLAG_SELF) - ); - - if($z) - $default_perms = intval($z[0]['abook_my_perms']); - + $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($channel['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; $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 )", diff --git a/include/event.php b/include/event.php index 1fe6e6f7f..03ecaa0a7 100644 --- a/include/event.php +++ b/include/event.php @@ -400,8 +400,7 @@ function event_store_item($arr,$event) { } else { - $z = q("select * from channel where channel_hash = '%s' and channel_id = %d limit 1", - dbesc($event['event_xchan']), + $z = q("select * from channel where channel_id = %d limit 1", intval($arr['uid']) ); @@ -413,7 +412,7 @@ function event_store_item($arr,$event) { $item_arr['id'] = $item['id']; } else { - $wall = (($z) ? true : false); + $wall = (($z[0]['channel_hash'] == $event['event_xchan']) ? true : false); $item_flags = ITEM_THREAD_TOP; if($wall) { @@ -455,7 +454,14 @@ function event_store_item($arr,$event) { $item_arr['body'] = $prefix . format_event_bbcode($arr); - $item_arr['plink'] = z_root() . '/channel/' . $z[0]['channel_address'] . '/?f=&mid=' . $item_arr['mid']; + // if it's local send the permalink to the channel page. + // otherwise we'll fallback to /display/$message_id + + if($wall) + $item_arr['plink'] = z_root() . '/channel/' . $z[0]['channel_address'] . '/?f=&mid=' . $item_arr['mid']; + else + $item_arr['plink'] = z_root() . '/display/' . $item_arr['mid']; + $x = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($arr['event_xchan']) diff --git a/include/follow.php b/include/follow.php index c8bd3c500..421bdd083 100644 --- a/include/follow.php +++ b/include/follow.php @@ -13,6 +13,8 @@ require_once('include/zot.php'); function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) { + + $result = array('success' => false,'message' => ''); $a = get_app(); @@ -62,9 +64,9 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) $j = json_decode($ret['body'],true); } - if($is_red && $j) { + $my_perms = get_channel_default_perms($uid); - $my_perms = PERMS_W_STREAM|PERMS_W_MAIL; + if($is_red && $j) { $role = get_pconfig($uid,'system','permissions_role'); if($role) { @@ -135,7 +137,6 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) } } - $my_perms = 0; $their_perms = 0; $xchan_hash = ''; @@ -162,7 +163,6 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) if($r) { $xchan_hash = $r[0]['xchan_hash']; $their_perms = 0; - $my_perms = PERMS_W_STREAM|PERMS_W_MAIL; $role = get_pconfig($uid,'system','permissions_role'); if($role) { $x = get_role_perms($role); @@ -203,8 +203,9 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) return $result; } - $r = q("select count(*) as total from abook where abook_account = %d and ( abook_flags & ABOOK_FLAG_FEED )", - intval($aid) + $r = q("select count(*) as total from abook where abook_account = %d and ( abook_flags & %d )", + intval($aid), + intval(ABOOK_FLAG_FEED) ); if($r) $total_feeds = $r[0]['total']; diff --git a/include/html2bbcode.php b/include/html2bbcode.php index 6d6e6333b..9ffc85a82 100644 --- a/include/html2bbcode.php +++ b/include/html2bbcode.php @@ -16,7 +16,7 @@ function node2bbcode(&$doc, $oldnode, $attributes, $startbb, $endbb) function node2bbcodesub(&$doc, $oldnode, $attributes, $startbb, $endbb) { - $savestart = str_replace('$', '%', $startbb); + $savestart = str_replace('$', '\x01', $startbb); $replace = false; $xpath = new DomXPath($doc); @@ -37,7 +37,7 @@ function node2bbcodesub(&$doc, $oldnode, $attributes, $startbb, $endbb) foreach ($attributes as $attribute => $value) { - $startbb = str_replace('%'.++$i, '$1', $startbb); + $startbb = str_replace('\x01'.++$i, '$1', $startbb); if (strpos('*'.$startbb, '$1') > 0) { diff --git a/include/hubloc.php b/include/hubloc.php index 04c29315a..0a1b51331 100644 --- a/include/hubloc.php +++ b/include/hubloc.php @@ -170,4 +170,92 @@ function hubloc_change_primary($hubloc) { return true; } -
\ No newline at end of file + + +function xchan_store($arr) { + + if(! $arr['hash']) + $arr['hash'] = $arr['guid']; + if(! $arr['hash']) + return false; + + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($arr['hash']) + ); + if($r) + return true; + + if(! $arr['network']) + $arr['network'] = 'unknown'; + if(! $arr['name']) + $arr['name'] = 'unknown'; + if(! $arr['url']) + $arr['url'] = z_root(); + if(! $arr['photo']) + $arr['photo'] = 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') ", + dbesc($arr['hash']), + dbesc($arr['guid']), + dbesc($arr['guid_sig']), + dbesc($arr['pubkey']), + dbesc($arr['address']), + dbesc($arr['url']), + dbesc($arr['connurl']), + dbesc($arr['follow']), + dbesc($arr['connpage']), + dbesc($arr['name']), + dbesc($arr['network']), + dbesc($arr['instance_url']), + intval($arr['flags']), + dbesc(datetime_convert()) + ); + if(! $r) + return $r; + + $photos = import_profile_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' limit 1", + dbesc(datetime_convert()), + dbesc($photos[0]), + dbesc($photos[1]), + dbesc($photos[2]), + dbesc($photos[3]), + dbesc($arr['hash']) + ); + return $r; + +} + + +function xchan_fetch($arr) { + + $key = ''; + if($arr['hash']) { + $key = 'xchan_hash'; + $v = $arr['hash']; + } + elseif($arr['guid']) { + $key = 'xchan_guid'; + $v = $arr['guid']; + } + elseif($arr['address']) { + $key = 'xchan_addr'; + $v = $arr['address']; + } + + if(! $key) + return false; + + $r = q("select * from xchan where $key = '$v'"); + if(! $r) + return false; + + $ret = array(); + foreach($r as $k => $v) { + if($k === 'xchan_addr') + $ret['address'] = $v; + else + $ret[str_replace('xchan_','',$k)] = $v; + } + return $ret; +}
\ No newline at end of file diff --git a/include/identity.php b/include/identity.php index 07bfaebbd..b9ee00623 100644 --- a/include/identity.php +++ b/include/identity.php @@ -176,6 +176,7 @@ function create_identity($arr) { // save this for auto_friending $total_identities = $ret['total_identities']; + $nick = mb_strtolower(trim($arr['nickname'])); if(! $nick) { $ret['message'] = t('Nickname is required.'); @@ -347,10 +348,13 @@ function create_identity($arr) { dbesc($a->get_baseurl() . "/photo/profile/m/{$newuid}") ); - $myperms = 0; if($role_permissions) { $myperms = ((array_key_exists('perms_auto',$role_permissions) && $role_permissions['perms_auto']) ? intval($role_permissions['perms_accept']) : 0); } + else + $myperms = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|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; $r = q("insert into abook ( abook_account, abook_channel, abook_xchan, abook_closeness, abook_created, abook_updated, abook_flags, abook_my_perms ) values ( %d, %d, '%s', %d, '%s', '%s', %d, %d ) ", @@ -372,6 +376,8 @@ function create_identity($arr) { set_pconfig($newuid,'system','permissions_role',$arr['permissions_role']); if(array_key_exists('online',$role_permissions)) set_pconfig($newuid,'system','hide_presence',1-intval($role_permissions['online'])); + if(array_key_exists('perms_auto',$role_permissions)) + set_pconfig($newuid,'system','autoperms',(($role_permissions['perms_auto']) ? $role_permissions['perms_accept'] : 0)); } // Create a group with yourself as a member. This allows somebody to use it @@ -389,7 +395,8 @@ function create_identity($arr) { dbesc( t('Friends') ) ); if($r) { - q("update channel set channel_allow_gid = '%s' where channel_id = %d limit 1", + q("update channel set channel_default_group = '%s', channel_allow_gid = '%s' where channel_id = %d limit 1", + dbesc($r[0]['hash']), dbesc('<' . $r[0]['hash'] . '>'), intval($newuid) ); @@ -403,6 +410,7 @@ function create_identity($arr) { $accts = get_config('system','auto_follow'); if(($accts) && (! $total_identities)) { + require_once('include/follow.php'); if(! is_array($accts)) $accts = array($accts); foreach($accts as $acct) { @@ -1558,4 +1566,16 @@ function notifications_on($channel_id,$value) { intval($channel_id) ); return $x; +} + + +function get_channel_default_perms($uid) { + + $r = q("select abook_my_perms from abook where abook_channel = %d and abook_flags & %d limit 1", + intval($uid), + intval(ABOOK_FLAG_SELF) + ); + if($r) + return $r[0]['abook_my_perms']; + return 0; }
\ No newline at end of file diff --git a/include/items.php b/include/items.php index 40343d505..7e2bb4f18 100755 --- a/include/items.php +++ b/include/items.php @@ -98,6 +98,7 @@ function collect_recipients($item,&$private_envelope) { } } + // This is a somewhat expensive operation but important. // Don't send this item to anybody who isn't allowed to see it @@ -213,6 +214,7 @@ function can_comment_on_post($observer_xchan,$item) { break; case 'any connections': case 'contacts': + case 'authenticated': case '': if(array_key_exists('owner',$item)) { if(($item['owner']['abook_xchan']) && ($item['owner']['abook_their_perms'] & PERMS_W_COMMENT)) @@ -2516,7 +2518,7 @@ function item_store_update($arr,$allow_exec = false) { return $ret; } -function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id) { +function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id, $walltowall = false) { // We won't be able to sign Diaspora comments for authenticated visitors // - we don't have their private key @@ -2524,9 +2526,18 @@ function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id) // since Diaspora doesn't handle edits we can only do this for the original text and not update it. require_once('include/bb2diaspora.php'); - $signed_body = bb2diaspora_itembody($datarray); + $signed_body = bb2diaspora_itembody($datarray,$walltowall); + + if($walltowall) { + logger('wall to wall comment',LOGGER_DEBUG); + // post will come across with the owner's identity. Throw a preamble onto the post to indicate the true author. + $signed_body = "\n\n" + . '![' . $datarray['author']['xchan_name'] . '](' . $datarray['author']['xchan_photo_m'] . ')' + . '[' . $datarray['author']['xchan_name'] . '](' . $datarray['author']['xchan_url'] . ')' . "\n\n" + . $signed_body; + } - logger('mod_item: storing diaspora comment signature',LOGGER_DEBUG); + logger('storing diaspora comment signature',LOGGER_DEBUG); $diaspora_handle = $channel['channel_address'] . '@' . get_app()->get_hostname(); @@ -2963,7 +2974,15 @@ function tgroup_check($uid,$item) { // At this point we've determined that the person receiving this post was mentioned in it. // Now let's check if this mention was inside a reshare so we don't spam a forum - $body = preg_replace('/\[share(.*?)\[\/share\]/','',$item['body']); + + $body = $item['body']; + + if(array_key_exists('item_flags',$item) && ($item['item_flags'] & ITEM_OBSCURED) && $body) { + $key = get_config('system','prvkey'); + $body = crypto_unencapsulate(json_decode($body,true),$key); + } + + $body = preg_replace('/\[share(.*?)\[\/share\]/','',$body); $pattern = '/@\!?\[zrl\=' . preg_quote($term['url'],'/') . '\]' . preg_quote($term['term'] . '+','/') . '\[\/zrl\]/'; @@ -4117,10 +4136,13 @@ function first_post_date($uid,$wall = false) { * current flat list of all representative dates. */ -function list_post_dates($uid,$wall) { +function list_post_dates($uid,$wall,$mindate) { $dnow = datetime_convert('',date_default_timezone_get(),'now','Y-m-d'); - $dthen = first_post_date($uid,$wall); + if($mindate) + $dthen = datetime_convert('',date_default_timezone_get(),$mindate); + else + $dthen = first_post_date($uid,$wall); if(! $dthen) return array(); @@ -4130,7 +4152,7 @@ function list_post_dates($uid,$wall) { if(intval(substr($dnow,8)) > 28) $dnow = substr($dnow,0,8) . '28'; if(intval(substr($dthen,8)) > 28) - $dnow = substr($dthen,0,8) . '28'; + $dthen = substr($dthen,0,8) . '28'; $ret = array(); // Starting with the current month, get the first and last days of every @@ -4164,7 +4186,7 @@ function posted_dates($uid,$wall) { if(intval(substr($dnow,8)) > 28) $dnow = substr($dnow,0,8) . '28'; if(intval(substr($dthen,8)) > 28) - $dnow = substr($dthen,0,8) . '28'; + $dthen = substr($dthen,0,8) . '28'; $ret = array(); // Starting with the current month, get the first and last days of every @@ -4238,14 +4260,24 @@ function fetch_post_tags($items,$link = false) { -function zot_feed($uid,$observer_xchan,$mindate) { +function zot_feed($uid,$observer_xchan,$arr) { $result = array(); - $mindate = datetime_convert('UTC','UTC',$mindate); + $mindate = null; + $message_id = null; + + if(array_key_exists('mindate',$arr)) { + $mindate = datetime_convert('UTC','UTC',$arr['mindate']); + } + + if(array_key_exists('message_id',$arr)) { + $message_id = $arr['message_id']; + } + + if(! $mindate) $mindate = NULL_DATE; - $mindate = dbesc($mindate); logger('zot_feed: ' . $uid); @@ -4267,6 +4299,11 @@ function zot_feed($uid,$observer_xchan,$mindate) { else $limit = " limit 0, 50 "; + if($message_id) { + $sql_extra .= " and mid = '" . dbesc($message_id) . "' "; + $limit = ''; + } + $items = array(); if(is_sys_channel($uid)) { diff --git a/include/notifier.php b/include/notifier.php index 79a6886ad..c193db116 100644 --- a/include/notifier.php +++ b/include/notifier.php @@ -58,6 +58,7 @@ require_once('include/html2plain.php'); * expire channel_id * relay item_id (item was relayed to owner, we will deliver it as owner) * location channel_id + * request channel_id xchan_hash message_id * */ @@ -142,6 +143,7 @@ function notifier_run($argv, $argc){ $expire = false; + $request = false; $mail = false; $fsuggest = false; $top_level = false; @@ -175,6 +177,22 @@ function notifier_run($argv, $argc){ $channel = $s[0]; } + elseif($cmd === 'request') { + $channel_id = $item_id; + $xchan = $argv[3]; + $request_message_id = $argv[4]; + + $s = q("select * from channel where channel_id = %d limit 1", + intval($channel_id) + ); + if($s) + $channel = $s[0]; + + $private = true; + $recipients[] = $xchan; + $packet_type = 'request'; + $normal_mode = false; + } elseif($cmd === 'expire') { // FIXME @@ -550,6 +568,7 @@ function notifier_run($argv, $argc){ 'mail' => $mail, 'location' => $location, 'fsuggest' => $fsuggest, + 'request' => $request, 'normal_mode' => $normal_mode, 'packet_type' => $packet_type, 'walltowall' => $walltowall @@ -579,6 +598,21 @@ function notifier_run($argv, $argc){ dbesc('') ); } + elseif($packet_type === 'request') { + $n = zot_build_packet($channel,'request',$env_recips,$hub['hubloc_sitekey'],$hash,array('message_id' => $request_message_id)); + 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($channel['channel_account_id']), + intval($channel['channel_id']), + dbesc('zot'), + dbesc($hub['hubloc_callback']), + intval(1), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + dbesc($n), + dbesc('') + ); + } else { $n = zot_build_packet($channel,'notify',$env_recips,(($private) ? $hub['hubloc_sitekey'] : null),$hash); q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", diff --git a/include/onepoll.php b/include/onepoll.php index 98d52db93..7a81282b3 100644 --- a/include/onepoll.php +++ b/include/onepoll.php @@ -15,12 +15,6 @@ function onepoll_run($argv, $argc){ logger('onepoll: start'); - $manual_id = 0; - $generation = 0; - - $force = false; - $restart = false; - if(($argc > 1) && (intval($argv[1]))) $contact_id = intval($argv[1]); @@ -28,7 +22,7 @@ function onepoll_run($argv, $argc){ logger('onepoll: no contact'); return; } - + $d = datetime_convert(); $contacts = q("SELECT abook.*, xchan.*, account.* @@ -90,7 +84,8 @@ function onepoll_run($argv, $argc){ $x = zot_refresh($contact,$importer); $responded = false; - $updated = datetime_convert(); + $updated = datetime_convert(); + $connected = datetime_convert(); if(! $x) { // mark for death by not updating abook_connected, this is caught in include/poller.php q("update abook set abook_updated = '%s' where abook_id = %d limit 1", @@ -101,7 +96,7 @@ function onepoll_run($argv, $argc){ else { q("update abook set abook_updated = '%s', abook_connected = '%s' where abook_id = %d limit 1", dbesc($updated), - dbesc($updated), + dbesc($connected), intval($contact['abook_id']) ); $responded = true; @@ -120,7 +115,9 @@ function onepoll_run($argv, $argc){ if($fetch_feed) { $feedurl = str_replace('/poco/','/zotfeed/',$contact['xchan_connurl']); - $x = z_fetch_url($feedurl . '?f=&mindate=' . urlencode($last_update)); + $feedurl .= '?f=&mindate=' . urlencode($last_update); + + $x = z_fetch_url($feedurl); logger('feed_update: ' . print_r($x,true), LOGGER_DATA); @@ -143,8 +140,8 @@ function onepoll_run($argv, $argc){ } } - // fetch some items - // set last updated timestamp + + // update the poco details for this connection if($contact['xchan_connurl']) { $r = q("SELECT xlink_id from xlink diff --git a/include/permissions.php b/include/permissions.php index 61ac8aea3..186ba32d8 100644 --- a/include/permissions.php +++ b/include/permissions.php @@ -460,6 +460,7 @@ function get_role_perms($role) { $ret['channel_w_chat'] = PERMS_CONTACTS; $ret['channel_a_delegate'] = 0; $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_w_storage'] = 0; $ret['channel_r_pages'] = PERMS_PUBLIC; $ret['channel_w_pages'] = 0; $ret['channel_a_republish'] = PERMS_SPECIFIC; @@ -492,6 +493,7 @@ function get_role_perms($role) { $ret['channel_w_chat'] = PERMS_CONTACTS; $ret['channel_a_delegate'] = 0; $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_w_storage'] = 0; $ret['channel_r_pages'] = PERMS_PUBLIC; $ret['channel_w_pages'] = 0; $ret['channel_a_republish'] = PERMS_SPECIFIC; @@ -524,6 +526,7 @@ function get_role_perms($role) { $ret['channel_w_chat'] = PERMS_SPECIFIC; $ret['channel_a_delegate'] = 0; $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_w_storage'] = 0; $ret['channel_r_pages'] = PERMS_PUBLIC; $ret['channel_w_pages'] = 0; $ret['channel_a_republish'] = PERMS_SPECIFIC; @@ -555,6 +558,7 @@ function get_role_perms($role) { $ret['channel_w_chat'] = PERMS_CONTACTS; $ret['channel_a_delegate'] = 0; $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_w_storage'] = 0; $ret['channel_r_pages'] = PERMS_PUBLIC; $ret['channel_w_pages'] = 0; $ret['channel_a_republish'] = PERMS_SPECIFIC; @@ -586,6 +590,7 @@ function get_role_perms($role) { $ret['channel_w_chat'] = PERMS_CONTACTS; $ret['channel_a_delegate'] = 0; $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_w_storage'] = 0; $ret['channel_r_pages'] = PERMS_PUBLIC; $ret['channel_w_pages'] = 0; $ret['channel_a_republish'] = PERMS_SPECIFIC; @@ -618,6 +623,7 @@ function get_role_perms($role) { $ret['channel_w_chat'] = PERMS_SPECIFIC; $ret['channel_a_delegate'] = 0; $ret['channel_r_storage'] = PERMS_CONTACTS; + $ret['channel_w_storage'] = 0; $ret['channel_r_pages'] = PERMS_CONTACTS; $ret['channel_w_pages'] = 0; $ret['channel_a_republish'] = PERMS_SPECIFIC; @@ -649,6 +655,7 @@ function get_role_perms($role) { $ret['channel_w_chat'] = PERMS_CONTACTS; $ret['channel_a_delegate'] = 0; $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_w_storage'] = 0; $ret['channel_r_pages'] = PERMS_PUBLIC; $ret['channel_w_pages'] = 0; $ret['channel_a_republish'] = PERMS_NETWORK; @@ -681,6 +688,7 @@ function get_role_perms($role) { $ret['channel_w_chat'] = PERMS_CONTACTS; $ret['channel_a_delegate'] = 0; $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_w_storage'] = 0; $ret['channel_r_pages'] = PERMS_PUBLIC; $ret['channel_w_pages'] = 0; $ret['channel_a_republish'] = PERMS_SPECIFIC; @@ -710,6 +718,7 @@ function get_role_perms($role) { $ret['channel_w_chat'] = 0; $ret['channel_a_delegate'] = 0; $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_w_storage'] = 0; $ret['channel_r_pages'] = PERMS_PUBLIC; $ret['channel_w_pages'] = 0; $ret['channel_a_republish'] = PERMS_SPECIFIC; @@ -717,6 +726,40 @@ function get_role_perms($role) { break; + case 'repository': + $ret['perms_auto'] = true; + $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 + |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 + |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_CONTACTS; + $ret['channel_w_wall'] = PERMS_CONTACTS; + $ret['channel_w_tagwall'] = PERMS_CONTACTS; + $ret['channel_w_comment'] = PERMS_CONTACTS; + $ret['channel_w_mail'] = PERMS_CONTACTS; + $ret['channel_w_photos'] = PERMS_CONTACTS; + $ret['channel_w_chat'] = PERMS_CONTACTS; + $ret['channel_a_delegate'] = 0; + $ret['channel_r_storage'] = PERMS_PUBLIC; + $ret['channel_w_storage'] = PERMS_CONTACTS; + $ret['channel_r_pages'] = PERMS_PUBLIC; + $ret['channel_w_pages'] = PERMS_CONTACTS; + $ret['channel_a_republish'] = PERMS_SPECIFIC; + $ret['channel_w_like'] = PERMS_NETWORK; + + break; + + + default: break; @@ -734,6 +777,10 @@ function get_role_perms($role) { function role_selector($current) { + + if(! $current) + $current = 'custom'; + $roles = array( 'social' => array( t('Social Networking'), array('social' => t('Mostly Public'), 'social_restricted' => t('Restricted'), 'social_private' => t('Private'))), @@ -741,8 +788,8 @@ function role_selector($current) { array('forum' => t('Mostly Public'), 'forum_restricted' => t('Restricted'), 'forum_private' => t('Private'))), 'feed' => array( t('Feed Republish'), array('feed' => t('Mostly Public'), 'feed_restricted' => t('Restricted'))), - 'soapbox' => array( t('Celebrity/Soapbox'), - array('soapbox' => t('Mostly Public'))), + 'special' => array( t('Special Purpose'), + array('soapbox' => t('Celebrity/Soapbox'), 'repository' => t('Group Repository'))), 'other' => array( t('Other'), array('custom' => t('Custom/Expert Mode')))); $o = '<select name="permissions_role" id="privacy-role-select">'; diff --git a/include/photos.php b/include/photos.php index badbbd791..23c1ea826 100644 --- a/include/photos.php +++ b/include/photos.php @@ -178,7 +178,7 @@ function photo_upload($channel, $observer, $args) { if($args['title']) $p['title'] = $args['title']; if($args['description']) - $p['desciprion'] = $args['description']; + $p['description'] = $args['description']; $r1 = $ph->save($p); @@ -431,7 +431,7 @@ 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_HIDDEN : ITEM_VISIBLE); + $item_restrict = (($visible) ? ITEM_VISIBLE : ITEM_HIDDEN); $title = ''; $mid = item_message_id(); diff --git a/include/poller.php b/include/poller.php index 61298b0ab..026d84c62 100644 --- a/include/poller.php +++ b/include/poller.php @@ -25,6 +25,15 @@ function poller_run($argv, $argc){ if(! $interval) $interval = ((get_config('system','delivery_interval') === false) ? 3 : intval(get_config('system','delivery_interval'))); + // Check for a lockfile. If it exists, but is over an hour old, it's stale. Ignore it. + $lockfile = 'store/[data]/poller'; + if ((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600))) { + logger("poller: Already running"); + return; + } + + // Create a lockfile. Needs two vars, but $x doesn't need to contain anything. + file_put_contents($lockfile, $x); logger('poller: start'); @@ -114,8 +123,8 @@ function poller_run($argv, $argc){ if(($d2 != $d1) && ($h1 == $h2)) { - require_once('include/dir_fns.php'); - check_upstream_directory(); + require_once('include/dir_fns.php'); + check_upstream_directory(); call_hooks('cron_daily',datetime_convert()); @@ -296,6 +305,7 @@ function poller_run($argv, $argc){ $update = true; } else { + // if we've never connected with them, start the mark for death countdown from now if($c == NULL_DATE) { @@ -342,7 +352,6 @@ function poller_run($argv, $argc){ $update = true; } - } if((! $update) && (! $force)) @@ -375,7 +384,10 @@ function poller_run($argv, $argc){ } } } - + + //All done - clear the lockfile + @unlink($lockfile); + return; } diff --git a/include/reddav.php b/include/reddav.php index 86b3a00e4..c16e08e27 100644 --- a/include/reddav.php +++ b/include/reddav.php @@ -50,7 +50,7 @@ function RedChannelList(&$auth) { if ($r) { foreach ($r as $rr) { if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage')) { - logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DEBUG); + logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA); // @todo can't we drop '/cloud'? It gets stripped off anyway in RedDirectory $ret[] = new RedDAV\RedDirectory('/cloud/' . $rr['channel_address'], $auth); } @@ -188,7 +188,7 @@ function RedCollectionData($file, &$auth) { * @throw \Sabre\DAV\Exception\Forbidden */ function RedFileData($file, &$auth, $test = false) { - logger($file . (($test) ? ' (test mode) ' : ''), LOGGER_DEBUG); + logger($file . (($test) ? ' (test mode) ' : ''), LOGGER_DATA); $x = strpos($file, '/cloud'); if ($x === 0) { diff --git a/include/session.php b/include/session.php index b531688e2..8500e2cd3 100644 --- a/include/session.php +++ b/include/session.php @@ -84,8 +84,9 @@ function ref_session_destroy ($id) { function ref_session_gc($expire) { q("DELETE FROM session WHERE expire < %d", dbesc(time())); - q("OPTIMIZE TABLE session"); - return true; + if (! get_config('system','innodb')) + q("OPTIMIZE TABLE session"); + return true; } $gc_probability = 50; diff --git a/include/taxonomy.php b/include/taxonomy.php index 35605da22..fab31c73d 100644 --- a/include/taxonomy.php +++ b/include/taxonomy.php @@ -209,13 +209,35 @@ function tagblock($link,$uid,$count = 0,$authors = '',$flags = 0,$restrict = 0,$ if($r) { $o = '<div class="tagblock widget"><h3>' . t('Tags') . '</h3><div class="tags" align="center">'; foreach($r as $rr) { - $o .= '<a href="'.$link .'/' . '?f=&tag=' . urlencode($rr[0]).'" class="tag'.$rr[2].'">'.$rr[0].'</a> ' . "\r\n"; + $o .= '<span class="tag'.$rr[2].'">#</span><a href="'.$link .'/' . '?f=&tag=' . urlencode($rr[0]).'" class="tag'.$rr[2].'">'.$rr[0].'</a> ' . "\r\n"; } $o .= '</div></div>'; } return $o; } +function catblock($uid,$count = 0,$authors = '',$flags = 0,$restrict = 0,$type = TERM_CATEGORY) { + $o = ''; + $tab = 0; + + $r = tagadelic($uid,$count,$authors,$flags,$restrict,$type); + + if($r) { + $c = q("select channel_address from channel where channel_id = %d limit 1", + intval($uid) + ); + + $o = '<div class="tagblock widget"><h3>' . t('Categories') . '</h3><div class="tags" align="center">'; + foreach($r as $rr) { + $o .= '<a href="channel/' . $c[0]['channel_address']. '?f=&cat=' . urlencode($rr[0]).'" class="tag'.$rr[2].'">'.$rr[0].'</a> ' . "\r\n"; + } + $o .= '</div></div>'; + } + return $o; +} + + + function dir_tagblock($link,$r) { $o = ''; $tab = 0; diff --git a/include/widgets.php b/include/widgets.php index 8905df59a..dcad3eff6 100644 --- a/include/widgets.php +++ b/include/widgets.php @@ -330,19 +330,32 @@ function widget_archive($arr) { $wall = ((array_key_exists('wall', $arr)) ? intval($arr['wall']) : 0); $style = ((array_key_exists('style', $arr)) ? $arr['style'] : 'select'); + $showend = ((get_pconfig($uid,'system','archive_show_end_date')) ? true : false); + $mindate = get_pconfig($uid,'system','archive_mindate'); + $visible_years = get_pconfig($uid,'system','archive_visible_years'); + if(! $visible_years) + $visible_years = 5; + + $url = z_root() . '/' . $a->cmd; - $ret = list_post_dates($uid,$wall); + $ret = list_post_dates($uid,$wall,$mindate); if(! count($ret)) return ''; + $cutoff_year = intval(datetime_convert('',date_default_timezone_get(),'now','Y')) - $visible_years; + $cutoff = ((array_key_exists($cutoff_year,$ret))? true : false); + $o = replace_macros(get_markup_template('posted_date_widget.tpl'),array( '$title' => t('Archives'), - '$size' => ((count($ret) > 6) ? 6 : count($ret)), + '$size' => $visible_years, + '$cutoff_year' => $cutoff_year, + '$cutoff' => $cutoff, '$url' => $url, '$style' => $style, + '$showend' => $showend, '$dates' => $ret )); return $o; @@ -387,6 +400,17 @@ function widget_tagcloud_wall($arr) { return tagblock('search',$a->profile['profile_uid'],$limit,$a->profile['channel_hash'],ITEM_WALL); return ''; } +function widget_catcloud_wall($arr) { + $a = get_app(); + if((! $a->profile['profile_uid']) || (! $a->profile['channel_hash'])) + return ''; + if(! perm_is_allowed($a->profile['profile_uid'],get_observer_hash(),'view_stream')) + return ''; + + $limit = ((array_key_exists('limit',$arr)) ? intval($arr['limit']) : 50); + return catblock($a->profile['profile_uid'],$limit,$a->profile['channel_hash'],ITEM_WALL); + return ''; +} function widget_affinity($arr) { @@ -430,6 +454,8 @@ function widget_settings_menu($arr) { // Retrieve the 'self' address book entry for use in the auto-permissions link + $role = get_pconfig(local_user(),'system','permissions_role'); + $abk = q("select abook_id from abook where abook_channel = %d and ( abook_flags & %d ) limit 1", intval(local_user()), intval(ABOOK_FLAG_SELF) @@ -487,14 +513,15 @@ function widget_settings_menu($arr) { 'selected' => '' ), - array( - 'label' => t('Automatic Permissions (Advanced)'), + ); + + if($role === false || $role === 'custom') { + $tabs[] = array( + 'label' => t('Connection Default Permissions'), 'url' => $a->get_baseurl(true) . '/connedit/' . $abook_self_id, 'selected' => '' - ), - - - ); + ); + } if(feature_enabled(local_user(),'premium_channel')) { $tabs[] = array( diff --git a/include/zot.php b/include/zot.php index e96eae10d..bdc1f607f 100644 --- a/include/zot.php +++ b/include/zot.php @@ -5,7 +5,7 @@ require_once('include/items.php'); require_once('include/hubloc.php'); /** - * Red implementation of zot protocol. + * Red implementation of zot protocol. * * https://github.com/friendica/red/wiki/zot * https://github.com/friendica/red/wiki/Zot---A-High-Level-Overview @@ -20,8 +20,8 @@ require_once('include/hubloc.php'); * Generates a unique string for use as a zot guid using our DNS-based url, the channel nickname and some entropy. * The entropy ensures uniqueness against re-installs where the same URL and nickname are chosen. * NOTE: zot doesn't require this to be unique. Internally we use a whirlpool hash of this guid and the signature - * of this guid signed with the channel private key. This can be verified and should make the probability of - * collision of the verified result negligible within the constraints of our immediate universe. + * of this guid signed with the channel private key. This can be verified and should make the probability of + * collision of the verified result negligible within the constraints of our immediate universe. * * @param string channel_nickname = unique nickname of controlling entity * @@ -51,7 +51,7 @@ function make_xchan_hash($guid,$guid_sig) { /** * @function zot_get_hublocs($hash) - * Given a zot hash, return all distinct hubs. + * Given a zot hash, return all distinct hubs. * This function is used in building the zot discovery packet * and therefore should only be used by channels which are defined * on this hub @@ -71,7 +71,7 @@ function make_xchan_hash($guid,$guid_sig) { * hubloc_connect char(255) * hubloc_sitekey text * hubloc_updated datetime - * hubloc_connected datetime + * hubloc_connected datetime * */ @@ -85,26 +85,26 @@ function zot_get_hublocs($hash) { ); return $ret; } - + /** * * @function zot_build_packet($channel,$type = 'notify',$recipients = null, $remote_key = null, $secret = null) * builds a zot notification packet that you can either - * store in the queue with a message array or call zot_zot to immediately + * store in the queue with a message array or call zot_zot to immediately * zot it to the other side * * @param array $channel => sender channel structure * @param string $type => packet type: one of 'ping', 'pickup', 'purge', 'refresh', 'force_refresh', 'notify', 'auth_check' * @param array $recipients => envelope information, array ( 'guid' => string, 'guid_sig' => string ); empty for public posts * @param string $remote_key => optional public site key of target hub used to encrypt entire packet - * NOTE: remote_key and encrypted packets are required for 'auth_check' packets, optional for all others + * NOTE: remote_key and encrypted packets are required for 'auth_check' packets, optional for all others * @param string $secret => random string, required for packets which require verification/callback - * e.g. 'pickup', 'purge', 'notify', 'auth_check'. Packet types 'ping', 'force_refresh', and 'refresh' do not require verification + * e.g. 'pickup', 'purge', 'notify', 'auth_check'. Packet types 'ping', 'force_refresh', and 'refresh' do not require verification * * @returns string json encoded zot packet */ -function zot_build_packet($channel,$type = 'notify',$recipients = null, $remote_key = null, $secret = null) { +function zot_build_packet($channel,$type = 'notify',$recipients = null, $remote_key = null, $secret = null, $extra = null) { $data = array( 'type' => $type, @@ -129,6 +129,12 @@ function zot_build_packet($channel,$type = 'notify',$recipients = null, $remote_ $data['secret_sig'] = base64url_encode(rsa_sign($secret,$channel['channel_prvkey'])); } + if($extra) { + foreach($extra as $k => $v) + $data[$k] = $v; + } + + logger('zot_build_packet: ' . print_r($data,true), LOGGER_DATA); // Hush-hush ultra top-secret mode @@ -433,15 +439,15 @@ function zot_refresh($them,$channel = null, $force = false) { } } else { - $default_perms = 0; - // look for default permissions to apply in return - e.g. auto-friend - $z = q("select * from abook where abook_channel = %d and (abook_flags & %d) limit 1", - intval($channel['channel_id']), - intval(ABOOK_FLAG_SELF) - ); - - if($z) - $default_perms = intval($z[0]['abook_my_perms']); + $role = get_pconfig($channel['channel_id'],'system','permissions_role'); + if($role) { + $xx = get_role_perms($role); + if($xx['perms_auto']) + $default_perms = $xx['perms_accept']; + } + if(! $default_perms) + $default_perms = intval(get_pconfig($channel['channel_id'],'system','autoperms')); + // Keep original perms to check if we need to notify them $previous_perms = get_all_perms($channel['channel_id'],$x['hash']); @@ -1065,7 +1071,7 @@ function zot_import($arr, $sender_url) { if(array_key_exists('iv',$i['notify'])) { $i['notify'] = json_decode(crypto_unencapsulate($i['notify'],get_config('system','prvkey')),true); - } + } logger('zot_import: notify: ' . print_r($i['notify'],true), LOGGER_DATA); @@ -1075,6 +1081,9 @@ function zot_import($arr, $sender_url) { continue; } + $message_request = ((array_key_exists('message_id',$i['notify'])) ? true : false); + if($message_request) + logger('processing message request'); $i['notify']['sender']['hash'] = make_xchan_hash($i['notify']['sender']['guid'],$i['notify']['sender']['guid_sig']); $deliveries = null; @@ -1098,7 +1107,7 @@ function zot_import($arr, $sender_url) { // It's a specifically targetted post. If we were sent a public_scope hint (likely), // get rid of it so that it doesn't get stored and cause trouble. - if(array_key_exists('message',$i) && array_key_exists('public_scope',$i['message'])) + if(($i) && is_array($i) && array_key_exists('message',$i) && is_array($i['message']) && array_key_exists('public_scope',$i['message'])) unset($i['message']['public_scope']); $deliveries = $r; @@ -1176,7 +1185,7 @@ function zot_import($arr, $sender_url) { logger('Activity recipients: ' . print_r($deliveries,true), LOGGER_DATA); $relay = ((array_key_exists('flags',$i['message']) && in_array('relay',$i['message']['flags'])) ? true : false); - $result = process_delivery($i['notify']['sender'],$arr,$deliveries,$relay); + $result = process_delivery($i['notify']['sender'],$arr,$deliveries,$relay,false,$message_request); } elseif($i['message']['type'] === 'mail') { @@ -1373,7 +1382,7 @@ function allowed_public_recips($msg) { } -function process_delivery($sender,$arr,$deliveries,$relay,$public = false) { +function process_delivery($sender,$arr,$deliveries,$relay,$public = false,$request = false) { $result = array(); @@ -1436,6 +1445,25 @@ function process_delivery($sender,$arr,$deliveries,$relay,$public = false) { ); if(! $r) { $result[] = array($d['hash'],'comment parent not found',$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>',$arr['mid']); + + // We don't seem to have a copy of this conversation or at least the parent + // - so request a copy of the entire conversation to date. + // Don't do this if it's a relay post as we're the ones who are supposed to + // have the copy and we don't want the request to loop. + // Also don't do this if this comment came from a conversation request packet. + // It's possible that comments are allowed but posting isn't and that could + // cause a conversation fetch loop. We can detect these packets since they are + // delivered via a 'notify' packet type that has a message_id element in the + // initial zot packet (just like the corresponding 'request' packet type which + // makes the request). + // We'll also check the send_stream permission - because if it isn't allowed, + // the top level post is unlikely to be imported and + // this is just an exercise in futility. + + if((! $relay) && (! $request) && (! $public) + && perm_is_allowed($channel['channel_id'],$sender['hash'],'send_stream')) { + proc_run('php', 'include/notifier.php', 'request', $channel['channel_id'], $sender['hash'], $arr['parent_mid']); + } continue; } if($relay) { @@ -2432,8 +2460,8 @@ function process_channel_sync_delivery($sender,$arr,$deliveries) { $channel = $r[0]; - $max_friends = service_class_fetch($channel['channel_id'],'total_channels'); - $max_feeds = account_service_class_fetch($channel['channel_account_id'],'total_feeds'); + $max_friends = service_class_fetch($channel['channel_id'],'total_channels'); + $max_feeds = account_service_class_fetch($channel['channel_account_id'],'total_feeds'); if($channel['channel_hash'] != $sender['hash']) { @@ -2519,7 +2547,7 @@ function process_channel_sync_delivery($sender,$arr,$deliveries) { continue; } $j = json_decode($f['body'],true); - if(! ($j['success'] && $j['guid'])) { + if(! ($j['success'] && $j['guid'])) { logger('process_channel_sync_delivery: probe failed.'); continue; } @@ -2618,8 +2646,8 @@ function process_channel_sync_delivery($sender,$arr,$deliveries) { intval($channel['channel_id']), intval($cl['visible']), intval($cl['deleted']), - dbesc($cl['name']) - ); + dbesc($cl['name']) + ); } // now look for any collections locally which weren't in the list we just received. @@ -2793,3 +2821,110 @@ function import_author_zot($x) { return false; } + +/** + * @function zot_process_message_request($data) + * If a site receives a comment to a post but finds they have no parent to attach it with, they + * may send a 'request' packet containing the message_id of the missing parent. This is the handler + * for that packet. We will create a message_list array of the entire conversation starting with + * the missing parent and invoke delivery to the sender of the packet. + * + * include/deliver.php (for local delivery) and mod/post.php (for web delivery) detect the existence of + * this 'message_list' at the destination and split it into individual messages which are + * processed/delivered in order. + * + * Called from mod/post.php + */ + + +function zot_process_message_request($data) { + $ret = array('success' => false); + + if(! $data['message_id']) { + $ret['message'] = 'no message_id'; + logger('no message_id'); + return $ret; + } + + $sender = $data['sender']; + $sender_hash = make_xchan_hash($sender['guid'],$sender['guid_sig']); + + /* + * Find the local channel in charge of this post (the first and only recipient of the request packet) + */ + + $arr = $data['recipients'][0]; + $recip_hash = make_xchan_hash($arr['guid'],$arr['guid_sig']); + $c = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_hash = '%s' limit 1", + dbesc($recip_hash) + ); + if(! $c) { + logger('recipient channel not found.'); + $ret['message'] .= 'recipient not found.' . EOL; + return $ret; + } + + /* + * fetch the requested conversation + */ + + $messages = zot_feed($c[0]['channel_id'],$sender_hash,array('message_id' => $data['message_id'])); + + 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) + and not (hubloc_status & %d) group by hubloc_sitekey", + dbesc($sender_hash), + intval(HUBLOC_FLAGS_DELETED), + intval(HUBLOC_OFFLINE) + ); + if(! $r) { + logger('no hubs'); + return $ret; + } + $hubs = $r; + $hublist = array(); + $keys = array(); + + $private = ((array_key_exists('flags',$messages[0]) && in_array('private',$messages[0]['flags'])) ? true : false); + if($private) + $env_recips = array('guid' => $sender['guid'],'guid_sig' => $sender['guid_sig'],'hash' => $sender_hash); + + $data_packet = json_encode(array('message_list' => $messages)); + + foreach($hubs as $hub) { + $hash = random_string(); + + /* + * create a notify packet and drop the actual message packet in the queue for pickup + */ + + $n = zot_build_packet($c[0],'notify',$env_recips,(($private) ? $hub['hubloc_sitekey'] : null),$hash,array('message_id' => $data['message_id'])); + 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($c[0]['channel_account_id']), + intval($c[0]['channel_id']), + dbesc('zot'), + dbesc($hub['hubloc_callback']), + intval(1), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + dbesc($n), + dbesc($data_packet) + ); + + /* + * invoke delivery to send out the notify packet + */ + + proc_run('php','include/deliver.php',$hash); + } + + } + $ret['success'] = true; + return $ret; +} |