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
This commit is contained in:
Habeas Codice
2014-11-13 13:06:31 -08:00
197 changed files with 19076 additions and 13281 deletions

View File

@@ -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 ++;
}
}
}
}

View File

@@ -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);
}

View File

@@ -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";

View File

@@ -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()
));

View File

@@ -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))

View File

@@ -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;
}

View File

@@ -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,11 +172,12 @@ 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);
$s = str_replace("\x00",'.',$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');

View File

@@ -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)) {

View File

@@ -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 )",

View File

@@ -64,14 +64,10 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
$j = json_decode($ret['body'],true);
}
$my_perms = get_channel_default_perms($uid);
if($is_red && $j) {
// 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;
$role = get_pconfig($uid,'system','permissions_role');
if($role) {
$x = get_role_perms($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);

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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'));
/**

View File

@@ -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;

View File

@@ -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();

View File

@@ -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))

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
}
}
}

View File

@@ -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())

View File

@@ -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).
// 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))
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);
}