diff options
author | Habeas Codice <habeascodice@federated.social> | 2014-11-13 13:06:31 -0800 |
---|---|---|
committer | Habeas Codice <habeascodice@federated.social> | 2014-11-13 13:06:31 -0800 |
commit | ac27db22c18ee7a82a52cbadb3efe2760b910499 (patch) | |
tree | aa7002d73dbcd4136033589f1cb135184f4126c1 /include | |
parent | 1a5a5c7edb8697c93f8bababbafa80245378dd7e (diff) | |
parent | 109cb936632c693d3f24afb9e2ce533797ad1a7f (diff) | |
download | volse-hubzilla-ac27db22c18ee7a82a52cbadb3efe2760b910499.tar.gz volse-hubzilla-ac27db22c18ee7a82a52cbadb3efe2760b910499.tar.bz2 volse-hubzilla-ac27db22c18ee7a82a52cbadb3efe2760b910499.zip |
Merge remote-tracking branch 'upstream/master'
Conflicts:
boot.php
include/dba/dba_driver.php
include/diaspora.php
include/follow.php
include/session.php
include/zot.php
mod/photos.php
mod/ping.php
Diffstat (limited to 'include')
-rw-r--r-- | include/Import/Importer.php | 94 | ||||
-rw-r--r-- | include/Import/refimport.php | 282 | ||||
-rw-r--r-- | include/bb2diaspora.php | 6 | ||||
-rw-r--r-- | include/contact_widgets.php | 3 | ||||
-rw-r--r-- | include/conversation.php | 8 | ||||
-rw-r--r-- | include/datetime.php | 13 | ||||
-rwxr-xr-x | include/dba/dba_driver.php | 153 | ||||
-rw-r--r-- | include/deliver.php | 7 | ||||
-rwxr-xr-x | include/diaspora.php | 21 | ||||
-rw-r--r-- | include/follow.php | 10 | ||||
-rw-r--r-- | include/identity.php | 21 | ||||
-rwxr-xr-x | include/items.php | 17 | ||||
-rw-r--r-- | include/nav.php | 2 | ||||
-rw-r--r-- | include/permissions.php | 6 | ||||
-rw-r--r-- | include/photos.php | 4 | ||||
-rw-r--r-- | include/poller.php | 6 | ||||
-rw-r--r-- | include/session.php | 5 | ||||
-rw-r--r-- | include/taxonomy.php | 24 | ||||
-rw-r--r-- | include/text.php | 22 | ||||
-rw-r--r-- | include/widgets.php | 32 | ||||
-rw-r--r-- | include/zot.php | 143 |
21 files changed, 750 insertions, 129 deletions
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/bb2diaspora.php b/include/bb2diaspora.php index 8a178d1ac..3c4f07568 100644 --- a/include/bb2diaspora.php +++ b/include/bb2diaspora.php @@ -277,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']) { @@ -388,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); @@ -462,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/contact_widgets.php b/include/contact_widgets.php index 28a9fcfd3..ee9394e95 100644 --- a/include/contact_widgets.php +++ b/include/contact_widgets.php @@ -29,8 +29,7 @@ function findpeople_widget() { '$random' => t('Random Profile'), '$inv' => t('Invite Friends'), '$advanced_search' => $advanced_search, - '$advanced_hint' => t('Exammple: name=fred and country=iceland'), - '$find_advanced' => t('Advanced Find'), + '$advanced_hint' => "\r\n" . t('Advanced example: name=fred and country=iceland'), '$loggedin' => local_user() )); diff --git a/include/conversation.php b/include/conversation.php index a531de9ba..c2258c20a 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -1493,8 +1493,12 @@ function network_tabs() { function profile_tabs($a, $is_owner=False, $nickname=Null){ - //echo "<pre>"; var_dump($a->user); killme(); - + + // Don't provide any profile tabs if we're running as the sys channel + + if($a->is_sys) + return; + $channel = $a->get_channel(); if (is_null($nickname)) diff --git a/include/datetime.php b/include/datetime.php index bfaa8792b..270be5e3d 100644 --- a/include/datetime.php +++ b/include/datetime.php @@ -134,10 +134,17 @@ function dob($dob) { if(! $f) $f = 'ymd'; - if ($dob && $dob != '0000-00-00') - $o = datesel($f,mktime(0,0,0,0,0,1900),mktime(),mktime(0,0,0,$month,$day,$year),'dob'); + if($dob === '0000-00-00') + $value = ''; else - $o = datesel($f,mktime(0,0,0,0,0,1900),mktime(),false,'dob'); + $value = (($year) ? datetime_convert('UTC','UTC',$dob,'Y-m-d') : datetime_convert('UTC','UTC',$dob,'m-d')); + + $o = '<input type="text" name="dob" value="' . $value . '" placeholder="' . t('YYYY-MM-DD or MM-DD') . '" />'; + +// if ($dob && $dob != '0000-00-00') +// $o = datesel($f,mktime(0,0,0,0,0,1900),mktime(),mktime(0,0,0,$month,$day,$year),'dob'); +// else +// $o = datesel($f,mktime(0,0,0,0,0,1900),mktime(),false,'dob'); return $o; } diff --git a/include/dba/dba_driver.php b/include/dba/dba_driver.php index 2dcdb0234..ddff80d7c 100755 --- a/include/dba/dba_driver.php +++ b/include/dba/dba_driver.php @@ -1,5 +1,26 @@ -<?php /** @file */ +<?php +/** + * @file dba_driver.php + * @brief some database related functions and abstract driver class. + * + * This file contains the abstract database driver class dba_driver and some + * functions for working with databases. + */ +/** + * @brief Returns the database driver object. + * + * If available it will use PHP's mysqli otherwise mysql driver. + * + * @param string $server DB server name + * @param string $port DB port + * @param string $user DB username + * @param string $pass DB password + * @param string $db database name + * @param string $dbtype 0 for mysql, 1 for postgres + * @param bool $install Defaults to false + * @return null|dba_driver A database driver object (dba_mysql|dba_mysqli) or null if no driver found. + */ function dba_factory($server, $port,$user,$pass,$db,$dbtype,$install = false) { $dba = null; @@ -23,7 +44,12 @@ function dba_factory($server, $port,$user,$pass,$db,$dbtype,$install = false) { return $dba; } - +/** + * @brief abstract database driver class. + * + * This class gets extended by the real database driver classes, e.g. dba_mysql, + * dba_mysqli. + */ abstract class dba_driver { // legacy behavior const INSTALL_SCRIPT='install/schema_mysql.sql'; @@ -35,16 +61,51 @@ abstract class dba_driver { public $connected = false; public $error = false; - abstract function connect($server, $port, $user,$pass,$db); + /** + * @brief Connect to the database. + * + * This abstract function needs to be implemented in the real driver. + * + * @param string $server DB server name + * @param string $port DB port + * @param string $user DB username + * @param string $pass DB password + * @param string $db database name + * @return bool + */ + abstract function connect($server, $port, $user, $pass, $db); + + /** + * @brief Perform a DB query with the SQL statement $sql. + * + * This abstract function needs to be implemented in the real driver. + * + * @param string $sql The SQL query to execute + */ abstract function q($sql); + + /** + * @brief Escape a string before being passed to a DB query. + * + * This abstract function needs to be implemented in the real driver. + * + * @param string $str The string to escape. + */ abstract function escape($str); + + /** + * @brief Close the database connection. + * + * This abstract function needs to be implemented in the real driver. + */ abstract function close(); + function __construct($server, $port, $user,$pass,$db,$install = false) { - if(($install) && (! $this->install($server, $port, $user,$pass,$db))) { + if(($install) && (! $this->install($server, $port, $user, $pass, $db))) { return; } - $this->connect($server, $port, $user,$pass,$db); + $this->connect($server, $port, $user, $pass, $db); } function get_null_date() { @@ -77,7 +138,11 @@ abstract class dba_driver { return true; } - + /** + * @brief Sets the database driver's debugging state. + * + * @param int $dbg 0 to disable debugging + */ function dbg($dbg) { $this->debug = $dbg; } @@ -107,10 +172,11 @@ abstract class dba_driver { function unescapebin($str) { return $str; } - -} +} // end abstract dba_driver class + +// Procedural functions function printable($s) { $s = preg_replace("~([\x01-\x08\x0E-\x0F\x10-\x1F\x7F-\xFF])~",".", $s); @@ -120,21 +186,35 @@ function printable($s) { return $s; } -// Procedural functions - +/** + * @brief set database driver debugging state. + * + * @param int $state 0 to disable debugging + */ function dbg($state) { global $db; + if($db) - $db->dbg($state); + $db->dbg($state); } - +/** + * @brief Escape strings being passed to DB queries. + * + * Always escape strings being used in DB queries. This function returns the + * escaped string. Integer DB parameters should all be proven integers by + * wrapping with intval(). + * + * @param string $str A string to pass to a DB query + * @return Return an escaped string of the value to pass to a DB query. + */ function dbesc($str) { global $db; + if($db && $db->connected) return($db->escape($str)); else - return(str_replace("'","\\'",$str)); + return(str_replace("'", "\\'", $str)); } function dbescbin($str) { global $db; @@ -186,59 +266,73 @@ function db_concat($fld, $sep) { // 'user', 1); +/** + * @brief Execute a SQL query with printf style args. + * + * printf style arguments %s and %d are replaced with variable arguments, which + * should each be appropriately dbesc() or intval(). + * SELECT queries return an array of results or false if SQL or DB error. Other + * queries return true if the command was successful or false if it wasn't. + * + * Example: + * $r = q("SELECT * FROM `%s` WHERE `uid` = %d", + * 'user', 1); + * + * @param string $sql The SQL query to execute + * @return bool|array + */ function q($sql) { - global $db; + $args = func_get_args(); unset($args[0]); if($db && $db->connected) { - $stmt = vsprintf($sql,$args); + $stmt = vsprintf($sql, $args); if($stmt === false) { - if(version_compare(PHP_VERSION,'5.4.0') >= 0) - logger('dba: vsprintf error: ' . print_r(debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT,1),true)); + if(version_compare(PHP_VERSION, '5.4.0') >= 0) + logger('dba: vsprintf error: ' . + print_r(debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1), true)); else - logger('dba: vsprintf error: ' . print_r(debug_backtrace(),true)); + logger('dba: vsprintf error: ' . print_r(debug_backtrace(), true)); } return $db->q($stmt); } - /** - * + /* * This will happen occasionally trying to store the * session data after abnormal program termination - * */ logger('dba: no database: ' . print_r($args,true)); - return false; + return false; } /** + * @brief Raw DB query, no arguments. * - * Raw db query, no arguments + * This function executes a raw DB query without any arguments. * + * @param string $sql The SQL query to execute */ - - function dbq($sql) { - global $db; + if($db && $db->connected) $ret = $db->q($sql); else $ret = false; + return $ret; } -// Caller is responsible for ensuring that any integer arguments to + +// Caller is responsible for ensuring that any integer arguments to // dbesc_array are actually integers and not malformed strings containing // SQL injection vectors. All integer array elements should be specifically // cast to int to avoid trouble. - - function dbesc_array_cb(&$item, $key) { if(is_string($item)) { if($item == '0000-00-00 00:00:00' && ACTIVE_DBTYPE == DBTYPE_POSTGRES) @@ -248,7 +342,6 @@ function dbesc_array_cb(&$item, $key) { } - function dbesc_array(&$arr) { if(is_array($arr) && count($arr)) { array_walk($arr,'dbesc_array_cb'); diff --git a/include/deliver.php b/include/deliver.php index a9f4fc220..47d8562df 100644 --- a/include/deliver.php +++ b/include/deliver.php @@ -40,6 +40,10 @@ function deliver_run($argv, $argc) { $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; @@ -48,8 +52,7 @@ function deliver_run($argv, $argc) { 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 - // also send 'request' packets to the webservice so it can decode the packet + if($r[0]['outq_msg']) { $m = json_decode($r[0]['outq_msg'],true); if(array_key_exists('message_list',$m)) { diff --git a/include/diaspora.php b/include/diaspora.php index 81ed9f3ab..09521b82b 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)>0 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/follow.php b/include/follow.php index af75354de..1abd0e3b9 100644 --- a/include/follow.php +++ b/include/follow.php @@ -64,13 +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); - // fixme - we need to be able to define these somewhere for the custom role - $my_perms = 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; + if($is_red && $j) { $role = get_pconfig($uid,'system','permissions_role'); if($role) { @@ -141,7 +137,6 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) } } - $my_perms = 0; $their_perms = 0; $xchan_hash = ''; @@ -168,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); diff --git a/include/identity.php b/include/identity.php index 11dab7744..a238959a5 100644 --- a/include/identity.php +++ b/include/identity.php @@ -348,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 ) ", @@ -373,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 @@ -885,6 +890,8 @@ function profile_sidebar($profile, $block = 0, $show_connect = true) { || (x($profile,'country_name') == 1)) $location = t('Location:'); + $profile['homepage'] = linkify($profile['homepage']); + $gender = ((x($profile,'gender') == 1) ? t('Gender:') : False); $marital = ((x($profile,'marital') == 1) ? t('Status:') : False); $homepage = ((x($profile,'homepage') == 1) ? t('Homepage:') : False); @@ -1561,4 +1568,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 d27d6e64c..6447de4e7 100755 --- a/include/items.php +++ b/include/items.php @@ -2974,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\]/'; @@ -4128,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(); diff --git a/include/nav.php b/include/nav.php index d4add7bcd..b4aa0f14a 100644 --- a/include/nav.php +++ b/include/nav.php @@ -173,7 +173,7 @@ EOT; $nav['search'] = array('search', t('Search'), "", t('Search site content')); - $nav['directory'] = array('directory', t('Directory'), "", t('Channel Locator')); + $nav['directory'] = array('directory', t('Directory'), "", t('Channel Directory')); /** diff --git a/include/permissions.php b/include/permissions.php index 14a531d8c..0ad28b3f1 100644 --- a/include/permissions.php +++ b/include/permissions.php @@ -549,7 +549,7 @@ function get_role_perms($role) { $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_stream'] = 0; $ret['channel_w_wall'] = PERMS_CONTACTS; $ret['channel_w_tagwall'] = PERMS_CONTACTS; $ret['channel_w_comment'] = PERMS_CONTACTS; @@ -581,7 +581,7 @@ function get_role_perms($role) { $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_stream'] = 0; $ret['channel_w_wall'] = PERMS_CONTACTS; $ret['channel_w_tagwall'] = PERMS_SPECIFIC; $ret['channel_w_comment'] = PERMS_CONTACTS; @@ -614,7 +614,7 @@ function get_role_perms($role) { $ret['channel_r_profile'] = PERMS_CONTACTS; $ret['channel_r_photos'] = PERMS_CONTACTS; $ret['channel_r_abook'] = PERMS_CONTACTS; - $ret['channel_w_stream'] = PERMS_CONTACTS; + $ret['channel_w_stream'] = 0; $ret['channel_w_wall'] = PERMS_CONTACTS; $ret['channel_w_tagwall'] = 0; $ret['channel_w_comment'] = PERMS_CONTACTS; diff --git a/include/photos.php b/include/photos.php index bdeb5db83..2393153c6 100644 --- a/include/photos.php +++ b/include/photos.php @@ -179,7 +179,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); @@ -432,7 +432,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 8e52d6e05..952431926 100644 --- a/include/poller.php +++ b/include/poller.php @@ -128,8 +128,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()); @@ -315,6 +315,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) { @@ -361,7 +362,6 @@ function poller_run($argv, $argc){ $update = true; } - } if((! $update) && (! $force)) diff --git a/include/session.php b/include/session.php index 282b99814..ed4dfdd16 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())); - db_optimizetable('session'); - return true; + if (! get_config('system','innodb')) + db_optimizetable('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/text.php b/include/text.php index 437bb8b5f..22a1a78c4 100644 --- a/include/text.php +++ b/include/text.php @@ -2025,12 +2025,22 @@ function json_decode_plus($s) { function design_tools() { + $channel = get_app()->get_channel(); + $sys = false; + + if(get_app()->is_sys && is_site_admin()) { + require_once('include/identity.php'); + $channel = get_sys_channel(); + $sys = true; + } + $who = $channel['channel_address']; return replace_macros(get_markup_template('design_tools.tpl'), array( '$title' => t('Design'), '$who' => $who, + '$sys' => $sys, '$blocks' => t('Blocks'), '$menus' => t('Menus'), '$layout' => t('Layouts'), @@ -2050,7 +2060,7 @@ function normalise_openid($s) { // used in ajax endless scroll request to find out all the args that the master page was viewing. // This was using $_REQUEST, but $_REQUEST also contains all your cookies. So we're restricting it -// to $_GET. If this is used in a post handler, that decision may need to be considered. +// to $_GET and $_POST. function extra_query_args() { $s = ''; @@ -2058,7 +2068,15 @@ function extra_query_args() { foreach($_GET as $k => $v) { // these are request vars we don't want to duplicate if(! in_array($k, array('q','f','zid','page','PHPSESSID'))) { - $s .= '&' . $k . '=' . $v; + $s .= '&' . $k . '=' . urlencode($v); + } + } + } + if(count($_POST)) { + foreach($_POST as $k => $v) { + // these are request vars we don't want to duplicate + if(! in_array($k, array('q','f','zid','page','PHPSESSID'))) { + $s .= '&' . $k . '=' . urlencode($v); } } } diff --git a/include/widgets.php b/include/widgets.php index cd0832846..74bdb5d74 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) { @@ -493,7 +517,7 @@ function widget_settings_menu($arr) { if($role === false || $role === 'custom') { $tabs[] = array( - 'label' => t('Automatic Permissions (Advanced)'), + 'label' => t('Connection Default Permissions'), 'url' => $a->get_baseurl(true) . '/connedit/' . $abook_self_id, 'selected' => '' ); @@ -561,7 +585,7 @@ function widget_design_tools($arr) { // otherwise local_user() is sufficient for permissions. if($a->profile['profile_uid']) - if($a->profile['profile_uid'] != local_user()) + if(($a->profile['profile_uid'] != local_user()) && (! $a->is_sys)) return ''; if(! local_user()) diff --git a/include/zot.php b/include/zot.php index 643aada58..2fd950acc 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,21 +85,21 @@ 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 */ @@ -441,15 +441,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)>0 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']); @@ -701,10 +701,10 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { $dirmode = get_config('system','directory_mode'); - if((($arr['site']['directory_mode'] === 'standalone') || ($dirmode & DIRECTORY_MODE_STANDALONE)) -&& ($arr['site']['url'] != z_root())) + if((($arr['site']['directory_mode'] === 'standalone') || ($dirmode & DIRECTORY_MODE_STANDALONE)) && ($arr['site']['url'] != z_root())) $arr['searchable'] = false; + $hidden = (1 - intval($arr['searchable'])); // Be careful - XCHAN_FLAGS_HIDDEN should evaluate to 1 @@ -723,6 +723,11 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { if($deleted_changed) $new_flags = $new_flags ^ XCHAN_FLAGS_DELETED; + $public_forum = (($r[0]['xchan_flags'] & XCHAN_FLAGS_PUBFORUM) ? true : false); + $pubforum_changed = ((intval($public_forum) != intval($arr['public_forum'])) ? true : false); + if($pubforum_changed) + $new_flags = $r[0]['xchan_flags'] ^ XCHAN_FLAGS_PUBFORUM; + if(($r[0]['xchan_name_date'] != $arr['name_updated']) || ($r[0]['xchan_connurl'] != $arr['connections_url']) || ($r[0]['xchan_flags'] != $new_flags) @@ -1073,7 +1078,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); @@ -1084,6 +1089,8 @@ function zot_import($arr, $sender_url) { } $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; @@ -1107,7 +1114,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; @@ -1446,15 +1453,24 @@ function process_delivery($sender,$arr,$deliveries,$relay,$public = false,$reque 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). - - if((! $relay) && (! $request)) + // 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) { @@ -2451,8 +2467,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']) { @@ -2538,7 +2554,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; } @@ -2636,8 +2652,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. @@ -2810,12 +2826,25 @@ 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); -// note: disabled until the loops stop. - return $ret; - if(! $data['message_id']) { $ret['message'] = 'no message_id'; logger('no message_id'); @@ -2825,6 +2854,10 @@ function zot_process_message_request($data) { $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", @@ -2835,20 +2868,27 @@ function zot_process_message_request($data) { $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 = '" . dbesc($sender_hash) . "' and not (hubloc_flags & %d)>0 + from hubloc where hubloc_hash = '%s' and not (hubloc_flags & %d)>0 and not (hubloc_status & %d)>0 group by hubloc_sitekey", - intval(HUBLOC_FLAGS_DELETED), - intval(HUBLOC_OFFLINE) - ); - if(! $r) { - logger('no hubs'); - return $ret; - } + dbesc($sender_hash), + intval(HUBLOC_FLAGS_DELETED), + intval(HUBLOC_OFFLINE) + ); + if(! $r) { + logger('no hubs'); + return $ret; + } $hubs = $r; $hublist = array(); $keys = array(); @@ -2856,10 +2896,16 @@ function zot_process_message_request($data) { $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 ) @@ -2875,6 +2921,11 @@ function zot_process_message_request($data) { dbesc($n), dbesc($data_packet) ); + + /* + * invoke delivery to send out the notify packet + */ + proc_run('php','include/deliver.php',$hash); } |