diff options
Diffstat (limited to 'include')
33 files changed, 1327 insertions, 677 deletions
diff --git a/include/ItemObject.php b/include/ItemObject.php index 512e12838..8be99d91e 100644 --- a/include/ItemObject.php +++ b/include/ItemObject.php @@ -346,6 +346,7 @@ class Item extends BaseObject { 'owner_photo' => $this->get_owner_photo(), 'owner_name' => $this->get_owner_name(), 'photo' => $body['photo'], + 'event' => $body['event'], 'has_tags' => $has_tags, // Item toolbar buttons diff --git a/include/RedDAV/RedBrowser.php b/include/RedDAV/RedBrowser.php index efea5d92f..1aa5f435e 100644 --- a/include/RedDAV/RedBrowser.php +++ b/include/RedDAV/RedBrowser.php @@ -188,7 +188,7 @@ class RedBrowser extends DAV\Browser\Plugin { $parentHash = ''; $owner = $this->auth->owner_id; - $splitPath = split('/', $fullPath); + $splitPath = explode('/', $fullPath); if (count($splitPath) > 3) { for ($i = 3; $i < count($splitPath); $i++) { $attachName = urldecode($splitPath[$i]); diff --git a/include/account.php b/include/account.php index b3a520fd4..e448bdcc6 100644 --- a/include/account.php +++ b/include/account.php @@ -67,7 +67,7 @@ function check_account_invite($invite_code) { $result['message'] .= t('An invitation is required.') . EOL; } $r = q("select * from register where `hash` = '%s' limit 1", dbesc($invite_code)); - if(! results($r)) { + if(! $r) { $result['message'] .= t('Invitation could not be verified.') . EOL; } } @@ -718,4 +718,4 @@ function upgrade_message($bbcode = false) { function upgrade_bool_message($bbcode = false) { $x = upgrade_link($bbcode); return t('This action is not available under your subscription plan.') . (($x) ? ' ' . $x : '') ; -}
\ No newline at end of file +} diff --git a/include/api.php b/include/api.php index f279b2aa3..5053977c5 100644 --- a/include/api.php +++ b/include/api.php @@ -1,10 +1,10 @@ <?php /** @file */ -require_once("bbcode.php"); -require_once("datetime.php"); -require_once("conversation.php"); -require_once("oauth.php"); -require_once("html2plain.php"); +require_once("include/bbcode.php"); +require_once("include/datetime.php"); +require_once("include/conversation.php"); +require_once("include/oauth.php"); +require_once("include/html2plain.php"); require_once('include/security.php'); require_once('include/photos.php'); require_once('include/items.php'); @@ -112,8 +112,11 @@ require_once('include/api_auth.php'); break; case "json": header ("Content-Type: application/json"); - foreach($r as $rr) + foreach($r as $rr) { + if(! $rr) + $rr = array(); $json = json_encode($rr); + } if ($_GET['callback']) $json = $_GET['callback']."(".$json.")"; return $json; @@ -248,6 +251,7 @@ require_once('include/api_auth.php'); if (count($uinfo)==0) { return False; } + $following = false; if(intval($uinfo[0]['abook_self'])) { $usr = q("select * from channel where channel_id = %d limit 1", @@ -263,18 +267,22 @@ require_once('include/api_auth.php'); $r = q("SELECT COUNT(`id`) as `count` FROM `item` WHERE `uid` = %d AND item_wall = 1 $item_normal - AND `allow_cid`='' AND `allow_gid`='' AND `deny_cid`='' AND `deny_gid`=''", + AND `allow_cid`='' AND `allow_gid`='' AND `deny_cid`='' AND `deny_gid`='' + AND item_private = 0 ", intval($usr[0]['channel_id']) ); $countitms = $r[0]['count']; + $following = true; } else { $r = q("SELECT COUNT(`id`) as `count` FROM `item` WHERE author_xchan = '%s' - AND `allow_cid`='' AND `allow_gid`='' AND `deny_cid`='' AND `deny_gid`=''", + AND `allow_cid`='' AND `allow_gid`='' AND `deny_cid`='' AND `deny_gid`='' + AND item_private = 0 ", intval($uinfo[0]['xchan_hash']) ); $countitms = $r[0]['count']; + $following = (($uinfo[0]['abook_myperms'] & PERMS_R_STREAM) ? true : false ); } @@ -310,7 +318,6 @@ require_once('include/api_auth.php'); 'location' => ($usr) ? $usr[0]['channel_location'] : '', 'profile_image_url' => $uinfo[0]['xchan_photo_l'], 'url' => $uinfo[0]['xchan_url'], -//FIXME 'contact_url' => $a->get_baseurl() . "/connections/".$uinfo[0]['abook_id'], 'protected' => false, 'friends_count' => intval($countfriends), @@ -334,7 +341,7 @@ require_once('include/api_auth.php'); 'profile_background_tile' => false, 'profile_use_background_image' => false, 'notifications' => false, - 'following' => '', // #XXX: fix me + 'following' => $following, 'verified' => true // #XXX: fix me ); @@ -382,7 +389,6 @@ require_once('include/api_auth.php'); function api_item_get_user(&$a, $item) { - global $usercache; // The author is our direct contact, in a conversation with us. @@ -396,11 +402,11 @@ require_once('include/api_auth.php'); $name = $item['author']['xchan_name']; // Generating a random ID - if (is_null($usercache[$nick]) or !array_key_exists($nick, $usercache)) - $usercache[$nick] = mt_rand(2000000, 2100000); + if (! $nick) + $nick = mt_rand(2000000, 2100000); $ret = array( - 'id' => $usercache[$nick], + 'id' => $nick, 'name' => $name, 'screen_name' => $nick, 'location' => '', //$uinfo[0]['default-location'], @@ -415,7 +421,7 @@ require_once('include/api_auth.php'); 'utc_offset' => 0, // #XXX: fix me 'time_zone' => '', //$uinfo[0]['timezone'], 'statuses_count' => 0, - 'following' => 1, + 'following' => false, 'statusnet_blocking' => false, 'notifications' => false, 'uid' => 0, @@ -853,13 +859,38 @@ require_once('include/api_auth.php'); $_REQUEST['type'] = 'wall'; if(x($_FILES,'media')) { - $_FILES['userfile'] = $_FILES['media']; - // upload the image if we have one - $_REQUEST['silent']='1'; //tell wall_upload function to return img info instead of echo - require_once('mod/wall_attach.php'); - $media = wall_attach_post($a); - if(strlen($media)>0) - $_REQUEST['body'] .= "\n\n".$media; + if(is_array($_FILES['media']['name'])) { + $num_uploads = count($_FILES['media']['name']); + for($x = 0; $x < $num_uploads; $x ++) { + $_FILES['userfile'] = array(); + $_FILES['userfile']['name'] = $_FILES['media']['name'][$x]; + $_FILES['userfile']['type'] = $_FILES['media']['type'][$x]; + $_FILES['userfile']['tmp_name'] = $_FILES['media']['tmp_name'][$x]; + $_FILES['userfile']['error'] = $_FILES['media']['error'][$x]; + $_FILES['userfile']['size'] = $_FILES['media']['size'][$x]; + + // upload each image if we have any + $_REQUEST['silent']='1'; //tell wall_upload function to return img info instead of echo + require_once('mod/wall_attach.php'); + $a->data['api_info'] = $user_info; + $media = wall_attach_post($a); + + if(strlen($media)>0) + $_REQUEST['body'] .= "\n\n" . $media; + } + } + else { + // AndStatus doesn't present media as an array + $_FILES['userfile'] = $_FILES['media']; + // upload each image if we have any + $_REQUEST['silent']='1'; //tell wall_upload function to return img info instead of echo + require_once('mod/wall_attach.php'); + $a->data['api_info'] = $user_info; + $media = wall_attach_post($a); + + if(strlen($media)>0) + $_REQUEST['body'] .= "\n\n" . $media; + } } } @@ -871,6 +902,7 @@ require_once('include/api_auth.php'); // this should output the last post (the one we just posted). return api_status_show($a,$type); } + api_register_func('api/statuses/update_with_media','api_statuses_update', true); api_register_func('api/statuses/update','api_statuses_update', true); @@ -1079,6 +1111,8 @@ require_once('include/api_auth.php'); 'contributors' => '' ); $status_info['user'] = $user_info; + if(array_key_exists('status',$status_info['user'])) + unset($status_info['user']['status']); } return api_apply_template("status", $type, array('$status' => $status_info)); @@ -1320,6 +1354,8 @@ require_once('include/api_auth.php'); // params $id = intval(argv(3)); + if(! $id) + $id = $_REQUEST['id']; logger('API: api_statuses_show: '.$id); @@ -1336,10 +1372,12 @@ require_once('include/api_auth.php'); $r = q("select * from item where true $item_normal $sql_extra", intval($id) ); + xchan_query($r,true); $ret = api_format_items($r,$user_info); + if ($conversation) { $data = array('$statuses' => $ret); return api_apply_template("timeline", $type, $data); @@ -2299,28 +2337,28 @@ require_once('include/api_auth.php'); api_register_func('api/direct_messages','api_direct_messages_inbox',true); - function api_oauth_request_token(&$a, $type){ try{ - $oauth = new FKOAuth1(); - $req = OAuthRequest::from_request(); -logger('Req: ' . var_export($req,true)); + $oauth = new ZotOAuth1(); + $req = OAuth1Request::from_request(); + logger('Req: ' . var_export($req,true),LOGGER_DATA); $r = $oauth->fetch_request_token($req); }catch(Exception $e){ logger('oauth_exception: ' . print_r($e->getMessage(),true)); - echo "error=". OAuthUtil::urlencode_rfc3986($e->getMessage()); + echo "error=". OAuth1Util::urlencode_rfc3986($e->getMessage()); killme(); } echo $r; killme(); } + function api_oauth_access_token(&$a, $type){ try{ - $oauth = new FKOAuth1(); - $req = OAuthRequest::from_request(); + $oauth = new ZotOAuth1(); + $req = OAuth1Request::from_request(); $r = $oauth->fetch_access_token($req); }catch(Exception $e){ - echo "error=". OAuthUtil::urlencode_rfc3986($e->getMessage()); killme(); + echo "error=". OAuth1Util::urlencode_rfc3986($e->getMessage()); killme(); } echo $r; killme(); diff --git a/include/api_auth.php b/include/api_auth.php index ee9db3f55..26a9df8d4 100644 --- a/include/api_auth.php +++ b/include/api_auth.php @@ -1,17 +1,19 @@ <?php /** @file */ -require_once("oauth.php"); - - /** - * Simple HTTP Login + * API Login via basic-auth or OAuth */ function api_login(&$a){ + + $record = null; + + require_once('include/oauth.php'); + // login with oauth try { - $oauth = new FKOAuth1(); - $req = OAuthRequest::from_request(); + $oauth = new ZotOAuth1(); + $req = OAuth1Request::from_request(); list($consumer,$token) = $oauth->verify_request($req); @@ -23,16 +25,14 @@ function api_login(&$a){ call_hooks('logged_in', $a->user); return; } - echo __file__.__line__.__function__."<pre>"; -// var_dump($consumer, $token); - die(); + killme(); } catch(Exception $e) { - logger(__file__.__line__.__function__."\n".$e); + logger($e->getMessage()); } - - // workaround for HTTP-auth in CGI mode + // workarounds for HTTP-auth in CGI mode + if(x($_SERVER,'REDIRECT_REMOTE_USER')) { $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"],6)) ; if(strlen($userpass)) { @@ -51,45 +51,49 @@ function api_login(&$a){ } } + require_once('include/auth.php'); + require_once('include/security.php'); - if (!isset($_SERVER['PHP_AUTH_USER'])) { - logger('API_login: ' . print_r($_SERVER,true), LOGGER_DEBUG); - header('WWW-Authenticate: Basic realm="Red"'); - header('HTTP/1.0 401 Unauthorized'); - die('This api requires login'); - } - // process normal login request - require_once('include/auth.php'); - $channel_login = 0; - $record = account_verify_password($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW']); - if(! $record) { - $r = q("select * from channel where channel_address = '%s' limit 1", + + if(isset($_SERVER['PHP_AUTH_USER'])) { + $channel_login = 0; + $record = account_verify_password($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW']); + if(! $record) { + $r = q("select * from channel left join account on account.account_id = channel.channel_account_id + where channel.channel_address = '%s' limit 1", dbesc($_SERVER['PHP_AUTH_USER']) ); if ($r) { - $x = q("select * from account where account_id = %d limit 1", - intval($r[0]['channel_account_id']) - ); - if ($x) { - $record = account_verify_password($x[0]['account_email'],$_SERVER['PHP_AUTH_PW']); + $record = account_verify_password($r[0]['account_email'],$_SERVER['PHP_AUTH_PW']); if($record) $channel_login = $r[0]['channel_id']; } } - if(! $record) { - logger('API_login failure: ' . print_r($_SERVER,true), LOGGER_DEBUG); - header('WWW-Authenticate: Basic realm="Red"'); - header('HTTP/1.0 401 Unauthorized'); - die('This api requires login'); - } } - require_once('include/security.php'); - authenticate_success($record); + if($record) { + authenticate_success($record); - if($channel_login) - change_channel($channel_login); + if($channel_login) + change_channel($channel_login); + + $_SESSION['allow_api'] = true; + return true; + } + else { + $_SERVER['PHP_AUTH_PW'] = '*****'; + logger('API_login failure: ' . print_r($_SERVER,true), LOGGER_DEBUG); + log_failed_login('API login failure'); + retry_basic_auth(); + } - $_SESSION['allow_api'] = true; } + + +function retry_basic_auth() { + header('WWW-Authenticate: Basic realm="Hubzilla"'); + header('HTTP/1.0 401 Unauthorized'); + echo('This api requires login'); + killme(); +}
\ No newline at end of file diff --git a/include/attach.php b/include/attach.php index 36b971712..8595d5d86 100644 --- a/include/attach.php +++ b/include/attach.php @@ -430,7 +430,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { $observer = $x[0]; } - logger('arr: ' . print_r($arr,true)); + logger('arr: ' . print_r($arr,true), LOGGER_DATA); if(! perm_is_allowed($channel_id,$observer_hash, 'write_storage')) { $ret['message'] = t('Permission denied.'); @@ -503,6 +503,10 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { } } + // AndStatus sends jpegs with a non-standard mimetype + if($type === 'image/jpg') + $type = 'image/jpeg'; + $existing_size = 0; if($options === 'replace') { diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php index 1be7caa19..81b95b30b 100644 --- a/include/bb2diaspora.php +++ b/include/bb2diaspora.php @@ -305,15 +305,6 @@ function bb2diaspora_itembody($item, $force_update = false) { $matches = array(); - //if we have a photo item just prepend the photo bbcode to item['body'] - $is_photo = (($item['obj_type'] == ACTIVITY_OBJ_PHOTO) ? true : false); - if($is_photo) { - $object = json_decode($item['object'],true); - if($object['bbcode']) { - $item['body'] = (($item['body']) ? $object['bbcode'] . "\r\n" . $item['body'] : $object['bbcode']); - } - } - if(($item['diaspora_meta']) && (! $force_update)) { $diaspora_meta = json_decode($item['diaspora_meta'],true); if($diaspora_meta) { @@ -333,6 +324,8 @@ function bb2diaspora_itembody($item, $force_update = false) { } } + create_export_photo_body($item); + $newitem = $item; if(array_key_exists('item_obscured',$item) && intval($item['item_obscured'])) { @@ -346,6 +339,7 @@ function bb2diaspora_itembody($item, $force_update = false) { } } + bb2diaspora_itemwallwall($newitem); $title = $newitem['title']; diff --git a/include/comanche.php b/include/comanche.php index 9585a6578..1537226ca 100644 --- a/include/comanche.php +++ b/include/comanche.php @@ -282,15 +282,21 @@ function comanche_widget($name, $text) { } } - if(file_exists('widget/' . trim($name) . '.php')) - require_once('widget/' . trim($name) . '.php'); + $func = 'widget_' . trim($name); + + if(! function_exists($func)) { + if(file_exists('widget/' . trim($name) . '.php')) + require_once('widget/' . trim($name) . '.php'); + elseif(folder_exists('widget/'. trim($name)) + && (file_exists('widget/' . trim($name) . '/' . trim($name) . '.php'))) + require_once('widget/' . trim($name) . '/' . trim($name) . '.php'); + } else { - $theme_widget = 'widget_' . trim($name) . '.php'; - if(theme_include($theme_widget)) + $theme_widget = $func . '.php'; + if((! function_exists($func)) && theme_include($theme_widget)) require_once(theme_include($theme_widget)); } - $func = 'widget_' . trim($name); if (function_exists($func)) return $func($vars); } diff --git a/include/conversation.php b/include/conversation.php index 2c447acbc..747bb5d0a 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -697,6 +697,7 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ 'thumb' => $profile_avatar, 'title' => $item['title'], 'body' => $body['html'], + 'event' => $body['event'], 'photo' => $body['photo'], 'tags' => $body['tags'], 'categories' => $body['categories'], @@ -1226,7 +1227,7 @@ function status_editor($a, $x, $popup = false) { '$wait' => t('Please wait'), '$permset' => t('Permission settings'), '$shortpermset' => t('permissions'), - '$ptyp' => (($notes_cid) ? 'note' : 'wall'), + '$ptyp' => '', '$content' => ((x($x,'body')) ? htmlspecialchars($x['body'], ENT_COMPAT,'UTF-8') : ''), '$attachment' => ((x($x, 'attachment')) ? $x['attachment'] : ''), '$post_id' => '', diff --git a/include/datetime.php b/include/datetime.php index f7df70a36..1d10e7ad7 100644 --- a/include/datetime.php +++ b/include/datetime.php @@ -235,7 +235,7 @@ function datetimesel($format, $min, $max, $default, $label, $id = 'datetimepicke $o .= replace_macros($tpl,array( '$field' => array($id, $label, $input_text, (($required) ? t('Required') : ''), (($required) ? '*' : ''), 'placeholder="' . $readable_format . '"'), )); - $o .= "<script>\$(function () {var picker = \$('#id_$id').datetimepicker({step:5,format:'$dateformat' $minjs $maxjs $pickers $defaultdatejs,dayOfWeekStart:$first_day}); $extra_js})</script>"; + $o .= "<script>\$(function () {var picker = \$('#id_$id').datetimepicker({step:15,format:'$dateformat' $minjs $maxjs $pickers $defaultdatejs,dayOfWeekStart:$first_day}); $extra_js})</script>"; return $o; } diff --git a/include/deliver.php b/include/deliver.php index de93e316e..7ff0fa125 100644 --- a/include/deliver.php +++ b/include/deliver.php @@ -2,6 +2,7 @@ require_once('include/cli_startup.php'); require_once('include/zot.php'); +require_once('include/queue_fn.php'); function deliver_run($argv, $argc) { @@ -15,7 +16,6 @@ function deliver_run($argv, $argc) { logger('deliver: invoked: ' . print_r($argv,true), LOGGER_DATA); - for($x = 1; $x < $argc; $x ++) { $dresult = null; @@ -24,87 +24,6 @@ function deliver_run($argv, $argc) { ); if($r) { - /** - * Check to see if we have any recent communications with this hub (in the last month). - * If not, reduce the outq_priority. - */ - - $base = ''; - - $h = parse_url($r[0]['outq_posturl']); - if($h) { - $base = $h['scheme'] . '://' . $h['host'] . (($h['port']) ? ':' . $h['port'] : ''); - if($base !== z_root()) { - $y = q("select site_update, site_dead from site where site_url = '%s' ", - dbesc($base) - ); - if($y) { - if(intval($y[0]['site_dead'])) { - q("delete from outq where outq_posturl = '%s'", - dbesc($r[0]['outq_posturl']) - ); - logger('dead site ignored ' . $base); - continue; - } - if($y[0]['site_update'] < datetime_convert('UTC','UTC','now - 1 month')) { - q("update outq set outq_priority = %d where outq_hash = '%s'", - intval($r[0]['outq_priority'] + 10), - dbesc($r[0]['outq_hash']) - ); - logger('immediate delivery deferred for site ' . $base); - continue; - } - } - else { - - // zot sites should all have a site record, unless they've been dead for as long as - // your site has existed. Since we don't know for sure what these sites are, - // call them unknown - - q("insert into site (site_url, site_update, site_dead, site_type) values ('%s','%s',0,%d) ", - dbesc($base), - dbesc(datetime_convert()), - intval(($r[0]['outq_driver'] === 'post') ? SITE_TYPE_NOTZOT : SITE_TYPE_UNKNOWN) - ); - } - } - } - - // "post" queue driver - used for diaspora and friendica-over-diaspora communications. - - if($r[0]['outq_driver'] === 'post') { - - - $result = z_post_url($r[0]['outq_posturl'],$r[0]['outq_msg']); - if($result['success'] && $result['return_code'] < 300) { - logger('deliver: queue post success to ' . $r[0]['outq_posturl'], LOGGER_DEBUG); - if($base) { - q("update site set site_update = '%s', site_dead = 0 where site_url = '%s' ", - dbesc(datetime_convert()), - dbesc($base) - ); - } - q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s' limit 1", - dbesc('accepted for delivery'), - dbesc(datetime_convert()), - dbesc($argv[$x]) - ); - - $y = q("delete from outq where outq_hash = '%s'", - dbesc($argv[$x]) - ); - - } - else { - logger('deliver: queue post returned ' . $result['return_code'] . ' from ' . $r[0]['outq_posturl'],LOGGER_DEBUG); - $y = q("update outq set outq_updated = '%s' where outq_hash = '%s'", - dbesc(datetime_convert()), - dbesc($argv[$x]) - ); - } - continue; - } - $notify = json_decode($r[0]['outq_notify'],true); // Messages without an outq_msg will need to go via the web, even if it's a @@ -127,9 +46,9 @@ function deliver_run($argv, $argc) { $msg = array('body' => json_encode(array('success' => true, 'pickup' => array(array('notify' => $notify,'message' => $m))))); $dresult = zot_import($msg,z_root()); } - $r = q("delete from outq where outq_hash = '%s'", - dbesc($argv[$x]) - ); + + remove_queue_item($r[0]['outq_hash']); + if($dresult && is_array($dresult)) { foreach($dresult as $xx) { if(is_array($xx) && array_key_exists('message_id',$xx)) { @@ -147,27 +66,16 @@ function deliver_run($argv, $argc) { } } - q("delete from dreport where dreport_queue = '%s' limit 1", - dbesc($argv[$x]) - ); - } - } - else { - logger('deliver: dest: ' . $r[0]['outq_posturl'], LOGGER_DEBUG); - $result = zot_zot($r[0]['outq_posturl'],$r[0]['outq_notify']); - if($result['success']) { - logger('deliver: remote zot delivery succeeded to ' . $r[0]['outq_posturl']); - zot_process_response($r[0]['outq_posturl'],$result, $r[0]); - } - else { - logger('deliver: remote zot delivery failed to ' . $r[0]['outq_posturl']); - logger('deliver: remote zot delivery fail data: ' . print_r($result,true), LOGGER_DATA); - $y = q("update outq set outq_updated = '%s' where outq_hash = '%s'", - dbesc(datetime_convert()), + q("delete from dreport where dreport_queue = '%s'", dbesc($argv[$x]) ); } } + + // otherwise it's a remote delivery - call queue_deliver(); + + queue_deliver($r[0],true); + } } } diff --git a/include/dir_fns.php b/include/dir_fns.php index b9f221bd1..fd2a5835d 100644 --- a/include/dir_fns.php +++ b/include/dir_fns.php @@ -22,7 +22,7 @@ function find_upstream_directory($dirmode) { $r = q("select * from site where site_url = '%s' limit 1", dbesc($preferred) ); - if(($r) && ($r[0]['site_flags'] & DIRECTORY_MODE_STADALONE)) { + if(($r) && ($r[0]['site_flags'] & DIRECTORY_MODE_STANDALONE)) { $preferred = ''; } } diff --git a/include/directory.php b/include/directory.php index 9ab1d805b..8792a15e1 100644 --- a/include/directory.php +++ b/include/directory.php @@ -8,6 +8,7 @@ require_once('boot.php'); require_once('include/zot.php'); require_once('include/cli_startup.php'); require_once('include/dir_fns.php'); +require_once('include/queue_fn.php'); /** * @brief @@ -83,20 +84,17 @@ function directory_run($argv, $argc){ */ $hash = random_string(); - q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) - values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", - dbesc($hash), - intval($channel['channel_account_id']), - intval($channel['channel_id']), - dbesc('zot'), - dbesc($url), - intval(1), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc($packet), - dbesc('') - ); - } else { + + queue_insert(array( + 'hash' => $hash, + 'account_id' => $channel['channel_account_id'], + 'channel_id' => $channel['channel_id'], + 'posturl' => $url, + 'notify' => $packet, + )); + + } + else { q("update channel set channel_dirdate = '%s' where channel_id = %d", dbesc(datetime_convert()), intval($channel['channel_id']) diff --git a/include/event.php b/include/event.php index e303ad232..539bfe484 100644 --- a/include/event.php +++ b/include/event.php @@ -21,35 +21,37 @@ function format_event_html($ev) { $bd_format = t('l F d, Y \@ g:i A') ; // Friday January 18, 2011 @ 8:01 AM - $o = '<div class="vevent">' . "\r\n"; + //todo: move this to template - $o .= '<p class="summary event-summary">' . bbcode($ev['summary']) . '</p>' . "\r\n"; + $o = '<div class="vevent">' . "\r\n"; - $o .= '<p class="description event-description">' . bbcode($ev['description']) . '</p>' . "\r\n"; + $o .= '<div class="event-title"><h3><i class="icon-calendar"></i> ' . bbcode($ev['summary']) . '</h3></div>' . "\r\n"; - $o .= '<p class="event-start">' . t('Starts:') . ' <abbr class="dtstart" title="' + $o .= '<div class="event-start"><span class="event-label">' . t('Starts:') . '</span> <span class="dtstart" title="' . datetime_convert('UTC', 'UTC', $ev['start'], (($ev['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )) . '" >' . (($ev['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(), $ev['start'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $ev['start'] , $bd_format))) - . '</abbr></p>' . "\r\n"; + . '</span></div>' . "\r\n"; if(! $ev['nofinish']) - $o .= '<p class="event-end" >' . t('Finishes:') . ' <abbr class="dtend" title="' + $o .= '<div class="event-end" ><span class="event-label">' . t('Finishes:') . '</span> <span class="dtend" title="' . datetime_convert('UTC','UTC',$ev['finish'], (($ev['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )) . '" >' . (($ev['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(), $ev['finish'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $ev['finish'] , $bd_format ))) - . '</abbr></p>' . "\r\n"; + . '</span></div>' . "\r\n"; + + $o .= '<div class="event-description">' . bbcode($ev['description']) . '</div>' . "\r\n"; if(strlen($ev['location'])) - $o .= '<p class="event-location"> ' . t('Location:') . ' <span class="location">' + $o .= '<div class="event-location"><span class="event-label"> ' . t('Location:') . '</span> <span class="location">' . bbcode($ev['location']) - . '</span></p>' . "\r\n"; + . '</span></div>' . "\r\n"; $o .= '</div>' . "\r\n"; @@ -785,6 +787,12 @@ function event_store_item($arr, $event) { 'type' => ACTIVITY_OBJ_EVENT, 'id' => z_root() . '/event/' . $r[0]['resource_id'], 'title' => $arr['summary'], + 'start' => $arr['start'], + 'finish' => $arr['finish'], + 'nofinish' => $arr['nofinish'], + 'description' => $arr['description'], + 'location' => $arr['location'], + 'adjust' => $arr['adjust'], 'content' => format_event_bbcode($arr), 'author' => array( 'name' => $r[0]['xchan_name'], @@ -887,7 +895,7 @@ function event_store_item($arr, $event) { $item_arr['verb'] = ACTIVITY_POST; $item_arr['item_wall'] = $item_wall; $item_arr['item_origin'] = $item_origin; - $item_arr['item_thread_top'] = $item_thread_top;; + $item_arr['item_thread_top'] = $item_thread_top; $attach = array(array( 'href' => z_root() . '/events/ical/' . urlencode($event['event_hash']), @@ -924,6 +932,12 @@ function event_store_item($arr, $event) { 'type' => ACTIVITY_OBJ_EVENT, 'id' => z_root() . '/event/' . $event['event_hash'], 'title' => $arr['summary'], + 'start' => $arr['start'], + 'finish' => $arr['finish'], + 'nofinish' => $arr['nofinish'], + 'description' => $arr['description'], + 'location' => $arr['location'], + 'adjust' => $arr['adjust'], 'content' => format_event_bbcode($arr), 'author' => array( 'name' => $x[0]['xchan_name'], diff --git a/include/externals.php b/include/externals.php index 18c034bb2..3a3a32420 100644 --- a/include/externals.php +++ b/include/externals.php @@ -28,7 +28,10 @@ function externals_run($argv, $argc){ } else { $randfunc = db_getfunc('RAND'); - $r = q("select site_url, site_pull from site where site_url != '%s' and site_flags != %d and site_type = %d order by $randfunc limit 1", + + // fixme this query does not deal with directory realms. + + $r = q("select site_url, site_pull from site where site_url != '%s' and site_flags != %d and site_type = %d and site_dead = 0 order by $randfunc limit 1", dbesc(z_root()), intval(DIRECTORY_MODE_STANDALONE), intval(SITE_TYPE_ZOT) @@ -37,19 +40,11 @@ function externals_run($argv, $argc){ $url = $r[0]['site_url']; } - // Note: blacklisted sites must be stored in the config as an array. - // No simple way to turn this into a personal config because we have no identity here. - // For that we probably need a variant of superblock. - $blacklisted = false; - $bl1 = get_config('system','blacklisted_sites'); - if(is_array($bl1) && $bl1) { - foreach($bl1 as $bl) { - if($bl && strpos($url,$bl) !== false) { - $blacklisted = true; - break; - } - } + + if(! check_siteallowed($url)) { + logger('blacklisted site: ' . $url); + $blacklisted = true; } $attempts ++; diff --git a/include/follow.php b/include/follow.php index 40ad2c299..97be82da7 100644 --- a/include/follow.php +++ b/include/follow.php @@ -161,6 +161,7 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) } } if($r) { + $xchan = $r[0]; $xchan_hash = $r[0]['xchan_hash']; $their_perms = 0; } @@ -172,7 +173,7 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) return $result; } - $x = array('channel_id' => $uid, 'follow_address' => $url, 'xchan' => $r[0], 'allowed' => 1); + $x = array('channel_id' => $uid, 'follow_address' => $url, 'xchan' => $r[0], 'allowed' => 1, 'singleton' => 0); call_hooks('follow_allow',$x); @@ -180,7 +181,7 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) $result['message'] = t('Protocol disabled.'); return $result; } - + $singleton = intval($x['singleton']); if((local_channel()) && $uid == local_channel()) { $aid = get_account_id(); @@ -221,13 +222,22 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) return $result; } - $r = q("select abook_xchan from abook where abook_xchan = '%s' and abook_channel = %d limit 1", + $r = q("select abook_xchan, abook_instance from abook where abook_xchan = '%s' and abook_channel = %d limit 1", dbesc($xchan_hash), intval($uid) ); if($r) { - $x = q("update abook set abook_their_perms = %d where abook_id = %d", + $abook_instance = $r[0]['abook_instance']; + + if(($singleton) && strpos($abook_instance,z_root()) === false) { + if($abook_instance) + $abook_instance .= ','; + $abook_instance .= z_root(); + } + + $x = q("update abook set abook_their_perms = %d, abook_instance = '%s' where abook_id = %d", intval($their_perms), + dbesc($abook_instance), intval($r[0]['abook_id']) ); } @@ -237,8 +247,8 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) if($closeness === false) $closeness = 80; - $r = q("insert into abook ( abook_account, abook_channel, abook_closeness, abook_xchan, abook_feed, abook_their_perms, abook_my_perms, abook_created, abook_updated ) - values( %d, %d, %d, '%s', %d, %d, %d, '%s', '%s' ) ", + $r = q("insert into abook ( abook_account, abook_channel, abook_closeness, abook_xchan, abook_feed, abook_their_perms, abook_my_perms, abook_created, abook_updated, abook_instance ) + values( %d, %d, %d, '%s', %d, %d, %d, '%s', '%s', '%s' ) ", intval($aid), intval($uid), intval($closeness), @@ -247,7 +257,8 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) intval(($is_http) ? $their_perms|PERMS_R_STREAM|PERMS_A_REPUBLISH : $their_perms), intval($my_perms), dbesc(datetime_convert()), - dbesc(datetime_convert()) + dbesc(datetime_convert()), + dbesc(($singleton) ? z_root() : '') ); } diff --git a/include/identity.php b/include/identity.php index 95ade3b28..98ba26bd8 100644 --- a/include/identity.php +++ b/include/identity.php @@ -896,12 +896,6 @@ function profile_load(&$a, $nickname, $profile = '') { $_SESSION['theme'] = $p[0]['channel_theme']; -// $a->set_template_engine(); // reset the template engine to the default in case the user's theme doesn't specify one - -// $theme_info_file = "view/theme/".current_theme()."/php/theme.php"; -// if (file_exists($theme_info_file)){ -// require_once($theme_info_file); -// } } /** diff --git a/include/items.php b/include/items.php index 7d349c631..44f9633a9 100755 --- a/include/items.php +++ b/include/items.php @@ -550,6 +550,7 @@ function get_public_feed($channel, $params) { $params['direction'] = ((x($params,'direction')) ? $params['direction'] : 'desc'); $params['pages'] = ((x($params,'pages')) ? intval($params['pages']) : 0); $params['top'] = ((x($params,'top')) ? intval($params['top']) : 0); + $params['cat'] = ((x($params,'cat')) ? $params['cat'] : ''); switch($params['type']) { case 'json': @@ -593,7 +594,8 @@ function get_feed_for($channel, $observer_hash, $params) { 'direction' => $params['direction'], // FIXME 'pages' => $params['pages'], 'order' => 'post', - 'top' => $params['top'] + 'top' => $params['top'], + 'cat' => $params['cat'] ), $channel, $observer_hash, CLIENT_MODE_NORMAL, get_app()->module); @@ -2347,7 +2349,7 @@ function item_store($arr, $allow_exec = false) { return $ret; } - if($arr['obj_type'] == ACTIVITY_OBJ_NOTE) + if(($arr['obj_type'] == ACTIVITY_OBJ_NOTE) && (! $arr['object'])) $arr['obj_type'] = ACTIVITY_OBJ_COMMENT; // is the new message multi-level threaded? @@ -2868,6 +2870,7 @@ function send_status_notifications($post_id,$item) { if($x) { foreach($x as $xx) { if($xx['author_xchan'] === $r[0]['channel_hash']) { + $notify = true; // check for an unfollow thread activity - we should probably decode the obj and check the id @@ -3332,7 +3335,6 @@ function start_delivery_chain($channel, $item, $item_id, $parent) { if((! $private) && $new_public_policy) $private = 1; - $item_wall = 1; $item_origin = 1; $item_uplink = 0; @@ -3383,8 +3385,13 @@ function start_delivery_chain($channel, $item, $item_id, $parent) { if($r) proc_run('php','include/notifier.php','tgroup',$item_id); - else + else { logger('start_delivery_chain: failed to update item'); + // reset the source xchan to prevent loops + $r = q("update item set source_xchan = '' where id = %d", + intval($item_id) + ); + } } /** @@ -3472,7 +3479,7 @@ function post_is_importable($item,$abook) { unobscure($item); $text = prepare_text($item['body'],$item['mimetype']); - $text = html2plain($text); + $text = html2plain(($item['title']) ? $item['title'] . ' ' . $text : $text); $lang = null; @@ -3947,6 +3954,8 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) { return '<at:deleted-entry ref="' . xmlify($item['mid']) . '" when="' . xmlify(datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME)) . '" />' . "\r\n"; + create_export_photo_body($item); + if($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid']) $body = fix_private_photos($item['body'],$owner['uid'],$item,$cid); else @@ -4817,6 +4826,9 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C if($arr['since_id']) $sql_extra .= " and item.id > " . $since_id . " "; + if($arr['cat']) + $sql_extra .= protect_sprintf(term_query('item', $arr['cat'], TERM_CATEGORY)); + if($arr['gid'] && $uid) { $r = q("SELECT * FROM `groups` WHERE id = %d AND uid = %d LIMIT 1", intval($arr['group']), diff --git a/include/js_strings.php b/include/js_strings.php index a21461a52..b1817f373 100644 --- a/include/js_strings.php +++ b/include/js_strings.php @@ -22,6 +22,7 @@ function js_strings() { '$submit' => t('Submit'), '$linkurl' => t('Please enter a link URL'), '$leavethispage' => t('Unsaved changes. Are you sure you wish to leave this page?'), + '$location' => t('Location'), '$t01' => ((t('timeago.prefixAgo') != 'timeago.prefixAgo') ? t('timeago.prefixAgo') : ''), '$t02' => ((t('timeago.prefixFromNow') != 'timeago.prefixFromNow') ? t('timeago.prefixFromNow') : ''), diff --git a/include/message.php b/include/message.php index 820d814b6..940fcc275 100644 --- a/include/message.php +++ b/include/message.php @@ -13,6 +13,7 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto=' $ret = array('success' => false); $a = get_app(); + $observer_hash = get_observer_hash(); if(! $recipient) { $ret['message'] = t('No recipient provided.'); @@ -148,8 +149,8 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto=' $match = null; $images = null; - if(preg_match_all("/\[zmg\](.*?)\[\/zmg\]/",((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$match)) - $images = $match[1]; + if(preg_match_all("/\[zmg\=([0-9]*)x([0-9]*)\](.*?)\[\/zmg\]/",((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$match)) + $images = $match[3]; $match = false; @@ -173,7 +174,7 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto=' 'revision' => $r['data']['revision'] ); } - $body = str_replace($match[1],'',$body); + $body = trim(str_replace($match[1],'',$body)); } } @@ -230,7 +231,7 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto=' dbesc($image_uri), intval($channel['channel_id']), dbesc('<' . $channel['channel_hash'] . '>') - ); + ); $r = q("UPDATE attach SET allow_cid = '%s' WHERE hash = '%s' AND is_photo = 1 and uid = %d and allow_cid = '%s'", dbesc('<' . $recipient . '>'), dbesc($image_uri), @@ -239,7 +240,7 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto=' ); } } - + if($attaches) { foreach($attaches as $attach) { $hash = substr($attach,0,strpos($attach,',')); @@ -505,3 +506,4 @@ function private_messages_fetch_conversation($channel_id, $messageitem_id, $upda return $messages; } + diff --git a/include/network.php b/include/network.php index 026f5ee0a..68452c3d1 100644 --- a/include/network.php +++ b/include/network.php @@ -1709,3 +1709,190 @@ function do_delivery($deliveries) { } + + +function get_site_info() { + + global $db; + global $a; + + $register_policy = Array('REGISTER_CLOSED', 'REGISTER_APPROVE', 'REGISTER_OPEN'); + $directory_mode = Array('DIRECTORY_MODE_NORMAL', 'DIRECTORY_MODE_SECONDARY','DIRECTORY_MODE_PRIMARY', 256 => 'DIRECTORY_MODE_STANDALONE'); + + $sql_extra = ''; + + $r = q("select * from channel left join account on account_id = channel_account_id where ( account_roles & 4096 )>0 and account_default_channel = channel_id"); + + + if($r) { + $admin = array(); + foreach($r as $rr) { + if($rr['channel_pageflags'] & PAGE_HUBADMIN) + $admin[] = array( 'name' => $rr['channel_name'], 'address' => $rr['channel_address'] . '@' . get_app()->get_hostname(), 'channel' => z_root() . '/channel/' . $rr['channel_address']); + } + if(! $admin) { + foreach($r as $rr) { + $admin[] = array( 'name' => $rr['channel_name'], 'address' => $rr['channel_address'] . '@' . get_app()->get_hostname(), 'channel' => z_root() . '/channel/' . $rr['channel_address']); + } + } + } + else { + $admin = false; + } + + $def_service_class = get_config('system','default_service_class'); + if($def_service_class) + $service_class = get_config('service_class',$def_service_class); + else + $service_class = false; + + $visible_plugins = array(); + if(is_array($a->plugins) && count($a->plugins)) { + $r = q("select * from addon where hidden = 0"); + if(count($r)) + foreach($r as $rr) + $visible_plugins[] = $rr['name']; + } + sort($visible_plugins); + + if(@is_dir('.git') && function_exists('shell_exec')) + $commit = trim(@shell_exec('git log -1 --format="%h"')); + if(! isset($commit) || strlen($commit) > 16) + $commit = ''; + + $site_info = get_config('system','info'); + $site_name = get_config('system','sitename'); + if(! get_config('system','hidden_version_siteinfo')) { + $version = RED_VERSION; + $tag = get_std_version(); + + if(@is_dir('.git') && function_exists('shell_exec')) { + $commit = trim( @shell_exec('git log -1 --format="%h"')); +// if(! get_config('system','hidden_tag_siteinfo')) +// $tag = trim( @shell_exec('git describe --tags --abbrev=0')); +// else +// $tag = ''; + } + if(! isset($commit) || strlen($commit) > 16) + $commit = ''; + } + else { + $version = $commit = ''; + } + + //Statistics + $channels_total_stat = intval(get_config('system','channels_total_stat')); + $channels_active_halfyear_stat = intval(get_config('system','channels_active_halfyear_stat')); + $channels_active_monthly_stat = intval(get_config('system','channels_active_monthly_stat')); + $local_posts_stat = intval(get_config('system','local_posts_stat')); + $hide_in_statistics = intval(get_config('system','hide_in_statistics')); + $site_expire = intval(get_config('system', 'default_expire_days')); + + + $data = Array( + 'version' => $version, + 'version_tag' => $tag, + 'commit' => $commit, + 'url' => z_root(), + 'plugins' => $visible_plugins, + 'register_policy' => $register_policy[get_config('system','register_policy')], + 'directory_mode' => $directory_mode[get_config('system','directory_mode')], + 'language' => get_config('system','language'), + 'rss_connections' => get_config('system','feed_contacts'), + 'expiration' => $site_expire, + 'default_service_restrictions' => $service_class, + 'admin' => $admin, + 'site_name' => (($site_name) ? $site_name : ''), + 'platform' => PLATFORM_NAME, + 'dbdriver' => $db->getdriver(), + 'lastpoll' => get_config('system','lastpoll'), + 'info' => (($site_info) ? $site_info : ''), + 'channels_total' => $channels_total_stat, + 'channels_active_halfyear' => $channels_active_halfyear_stat, + 'channels_active_monthly' => $channels_active_monthly_stat, + 'local_posts' => $local_posts_stat, + 'hide_in_statistics' => $hide_in_statistics + ); + return $data; +} + + + +function check_siteallowed($url) { + + $retvalue = true; + + + $arr = array('url' => $url); + call_hooks('check_siteallowed',$arr); + + if(array_key_exists('allowed',$arr)) + return $arr['allowed']; + + $bl1 = get_config('system','whitelisted_sites'); + if(is_array($bl1) && $bl1) { + foreach($bl1 as $bl) { + if($bl1 === '*') + $retvalue = true; + if($bl && strpos($url,$bl) !== false) + return true; + } + } + $bl1 = get_config('system','blacklisted_sites'); + if(is_array($bl1) && $bl1) { + foreach($bl1 as $bl) { + if($bl1 === '*') + $retvalue = false; + if($bl && strpos($url,$bl) !== false) { + return false; + } + } + } + return $retvalue; +} + +function check_channelallowed($hash) { + + $retvalue = true; + + $arr = array('hash' => $hash); + call_hooks('check_channelallowed',$arr); + + if(array_key_exists('allowed',$arr)) + return $arr['allowed']; + + $bl1 = get_config('system','whitelisted_channels'); + if(is_array($bl1) && $bl1) { + foreach($bl1 as $bl) { + if($bl1 === '*') + $retvalue = true; + if($bl && strpos($hash,$bl) !== false) + return true; + } + } + $bl1 = get_config('system','blacklisted_channels'); + if(is_array($bl1) && $bl1) { + foreach($bl1 as $bl) { + if($bl1 === '*') + $retvalue = false; + if($bl && strpos($hash,$bl) !== false) { + return false; + } + } + } + return $retvalue; +} + +function deliverable_singleton($xchan) { + $r = q("select abook_instance from abook where abook_xchan = '%s' limit 1", + dbesc($xchan['xchan_hash']) + ); + if($r) { + if(! $r[0]['abook_instance']) + return true; + if(strpos($r[0]['abook_instance'],z_root()) !== false) + return true; + } + return false; +} + diff --git a/include/notifier.php b/include/notifier.php index b7830285a..50981df9d 100644 --- a/include/notifier.php +++ b/include/notifier.php @@ -44,7 +44,6 @@ require_once('include/html2plain.php'); * expire (in items.php) * like (in like.php, poke.php) * mail (in message.php) - * suggest (in fsuggest.php) * tag (in photos.php, poke.php, tagger.php) * tgroup (in items.php) * wall-new (in photos.php, item.php) @@ -52,11 +51,14 @@ require_once('include/html2plain.php'); * and ITEM_ID is the id of the item in the database that needs to be sent to others. * * ZOT + * permission_create abook_id * permission_update abook_id * refresh_all channel_id * purge_all channel_id * expire channel_id * relay item_id (item was relayed to owner, we will deliver it as owner) + * single_activity item_id (deliver to a singleton network from the appropriate clone) + * single_mail mail_id (deliver to a singleton network from the appropriate clone) * location channel_id * request channel_id xchan_hash message_id * rating xlink_id @@ -66,6 +68,12 @@ require_once('include/html2plain.php'); require_once('include/cli_startup.php'); require_once('include/zot.php'); require_once('include/queue_fn.php'); +require_once('include/session.php'); +require_once('include/datetime.php'); +require_once('include/items.php'); +require_once('include/bbcode.php'); +require_once('include/identity.php'); +require_once('include/Contact.php'); function notifier_run($argv, $argc){ @@ -73,15 +81,10 @@ function notifier_run($argv, $argc){ $a = get_app(); - require_once("session.php"); - require_once("datetime.php"); - require_once('include/items.php'); - require_once('include/bbcode.php'); if($argc < 3) return; - logger('notifier: invoked: ' . print_r($argv,true), LOGGER_DEBUG); $cmd = $argv[1]; @@ -93,7 +96,6 @@ function notifier_run($argv, $argc){ if(! $item_id) return; - require_once('include/identity.php'); $sys = get_sys_channel(); $deliveries = array(); @@ -108,87 +110,8 @@ function notifier_run($argv, $argc){ } - if($cmd == 'permission_update' || $cmd == 'permission_create') { - // Get the recipient - $r = q("select abook.*, hubloc.* from abook - left join hubloc on hubloc_hash = abook_xchan - where abook_id = %d and abook_self = 0 - and not (hubloc_flags & %d) > 0 and not (hubloc_status & %d) > 0 limit 1", - intval($item_id), - intval(HUBLOC_FLAGS_DELETED), - intval(HUBLOC_OFFLINE) - ); - - if($r) { - // Get the sender - $s = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1", - intval($r[0]['abook_channel']) - ); - if($s) { - $perm_update = array('sender' => $s[0], 'recipient' => $r[0], 'success' => false, 'deliveries' => ''); - - if($cmd == 'permission_create') - call_hooks('permissions_create',$perm_update); - else - call_hooks('permissions_update',$perm_update); - - if($perm_update['success'] && $perm_update['deliveries']) - $deliveries[] = $perm_update['deliveries']; - - if(! $perm_update['success']) { - // send a refresh message to each hub they have registered here - $h = q("select * from hubloc where hubloc_hash = '%s' - and not (hubloc_flags & %d) > 0 and not (hubloc_status & %d) > 0", - dbesc($r[0]['hubloc_hash']), - intval(HUBLOC_FLAGS_DELETED), - intval(HUBLOC_OFFLINE) - ); - if($h) { - foreach($h as $hh) { - if(in_array($hh['hubloc_url'],$dead_hubs)) { - logger('skipping dead hub: ' . $hh['hubloc_url'], LOGGER_DEBUG); - continue; - } - - $data = zot_build_packet($s[0],'refresh',array(array( - 'guid' => $hh['hubloc_guid'], - 'guid_sig' => $hh['hubloc_guid_sig'], - 'url' => $hh['hubloc_url']) - )); - if($data) { - $hash = random_string(); - q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) - values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", - dbesc($hash), - intval($s[0]['channel_account_id']), - intval($s[0]['channel_id']), - dbesc('zot'), - dbesc($hh['hubloc_callback']), - intval(1), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc($data), - dbesc('') - ); - $deliveries[] = $hash; - } - } - - } - } - - if($deliveries) - do_delivery($deliveries); - } - } - return; - } - - - $expire = false; $request = false; $mail = false; - $fsuggest = false; $top_level = false; $location = false; $recipients = array(); @@ -237,51 +160,42 @@ function notifier_run($argv, $argc){ $packet_type = 'request'; $normal_mode = false; } - elseif($cmd === 'expire') { - - // FIXME - // This will require a special zot packet containing a list of item message_id's to be expired. - // This packet will be public, since we cannot selectively deliver here. - // We need the handling on this end to create the array, and the handling on the remote end - // to verify permissions (for each item) and process it. Until this is complete, the expire feature will be disabled. - - return; - - $normal_mode = false; - $expire = true; - $items = q("SELECT * FROM item WHERE uid = %d AND item_wall = 1 - AND item_deleted = 1 AND `changed` > %s - INTERVAL %s", - intval($item_id), - db_utcnow(), db_quoteinterval('10 MINUTE') + elseif($cmd == 'permission_update' || $cmd == 'permission_create') { + // Get the (single) recipient + $r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_self = 0", + intval($item_id) ); - $uid = $item_id; - $item_id = 0; - if(! $items) - return; + if($r) { + $uid = $r[0]['abook_channel']; + // Get the sender + $channel = channelx_by_n($uid); + if($channel) { + $perm_update = array('sender' => $channel, 'recipient' => $r[0], 'success' => false, 'deliveries' => ''); - } - elseif($cmd === 'suggest') { - $normal_mode = false; - $fsuggest = true; + if($cmd == 'permission_create') + call_hooks('permissions_create',$perm_update); + else + call_hooks('permissions_update',$perm_update); - $suggest = q("SELECT * FROM `fsuggest` WHERE `id` = %d LIMIT 1", - intval($item_id) - ); - if(! count($suggest)) - return; - $uid = $suggest[0]['uid']; - $recipients[] = $suggest[0]['cid']; - $item = $suggest[0]; + if($perm_update['success']) { + if($perm_update['deliveries']) { + $deliveries[] = $perm_update['deliveries']; + do_delivery($deliveries); + } + return; + } + else { + $recipients[] = $r[0]['abook_xchan']; + $private = false; + $packet_type = 'refresh'; + } + } + } } elseif($cmd === 'refresh_all') { logger('notifier: refresh_all: ' . $item_id); - $s = q("select * from channel where channel_id = %d limit 1", - intval($item_id) - ); - if($s) - $channel = $s[0]; $uid = $item_id; - $recipients = array(); + $channel = channelx_by_n($item_id); $r = q("select abook_xchan from abook where abook_channel = %d", intval($item_id) ); @@ -464,9 +378,12 @@ function notifier_run($argv, $argc){ // if our parent is a tag_delivery recipient, uplink to the original author causing // a delivery fork. - if(intval($parent_item['item_uplink']) && (! $top_level_post) && ($cmd !== 'uplink')) { - logger('notifier: uplinking this item'); - proc_run('php','include/notifier.php','uplink',$item_id); + if(($parent_item) && intval($parent_item['item_uplink']) && (! $top_level_post) && ($cmd !== 'uplink')) { + // don't uplink a relayed post to the relay owner + if($parent_item['source_xchan'] !== $parent_item['owner_xchan']) { + logger('notifier: uplinking this item'); + proc_run('php','include/notifier.php','uplink',$item_id); + } } $private = false; @@ -605,10 +522,8 @@ function notifier_run($argv, $argc){ 'relay_to_owner' => $relay_to_owner, 'uplink' => $uplink, 'cmd' => $cmd, - 'expire' => $expire, 'mail' => $mail, 'location' => $location, - 'fsuggest' => $fsuggest, 'request' => $request, 'normal_mode' => $normal_mode, 'packet_type' => $packet_type, @@ -628,52 +543,38 @@ function notifier_run($argv, $argc){ // default: zot protocol - $hash = random_string(); + $packet = null; + if($packet_type === 'refresh' || $packet_type === 'purge') { - $n = zot_build_packet($channel,$packet_type); - q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", - dbesc($hash), - intval($channel['channel_account_id']), - intval($channel['channel_id']), - dbesc('zot'), - dbesc($hub['hubloc_callback']), - intval(1), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc($n), - dbesc('') - ); + $packet = zot_build_packet($channel,$packet_type); } elseif($packet_type === 'request') { - $n = zot_build_packet($channel,'request',$env_recips,$hub['hubloc_sitekey'],$hash,array('message_id' => $request_message_id)); - q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", - dbesc($hash), - intval($channel['channel_account_id']), - intval($channel['channel_id']), - dbesc('zot'), - dbesc($hub['hubloc_callback']), - intval(1), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc($n), - dbesc('') + $packet = zot_build_packet($channel,$packet_type,$env_recips,$hub['hubloc_sitekey'],$hash, + array('message_id' => $request_message_id) ); } + + if($packet) { + queue_insert(array( + 'hash' => $hash, + 'account_id' => $channel['channel_account_id'], + 'channel_id' => $channel['channel_id'], + 'posturl' => $hub['hubloc_callback'], + 'notify' => $packet + )); + } else { - $n = zot_build_packet($channel,'notify',$env_recips,(($private) ? $hub['hubloc_sitekey'] : null),$hash); - q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", - dbesc($hash), - intval($target_item['aid']), - intval($target_item['uid']), - dbesc('zot'), - dbesc($hub['hubloc_callback']), - intval(1), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc($n), - dbesc(json_encode($encoded_item)) - ); + $packet = zot_build_packet($channel,'notify',$env_recips,(($private) ? $hub['hubloc_sitekey'] : null),$hash); + queue_insert(array( + 'hash' => $hash, + 'account_id' => $target_item['aid'], + 'channel_id' => $target_item['uid'], + 'posturl' => $hub['hubloc_callback'], + 'notify' => $packet, + 'msg' => json_encode($encoded_item) + )); + // only create delivery reports for normal undeleted items if(is_array($target_item) && array_key_exists('postopts',$target_item) && (! $target_item['item_deleted'])) { q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan, dreport_queue ) values ( '%s','%s','%s','%s','%s','%s','%s' ) ", diff --git a/include/oauth.php b/include/oauth.php index 80336f906..f3d144158 100644 --- a/include/oauth.php +++ b/include/oauth.php @@ -1,4 +1,5 @@ <?php /** @file */ + /** * OAuth server * Based on oauth2-php <http://code.google.com/p/oauth2-php/> @@ -9,16 +10,17 @@ define('REQUEST_TOKEN_DURATION', 300); define('ACCESS_TOKEN_DURATION', 31536000); require_once("library/OAuth1.php"); -require_once("library/oauth2-php/lib/OAuth2.inc"); -class FKOAuthDataStore extends OAuthDataStore { - function gen_token(){ +//require_once("library/oauth2-php/lib/OAuth2.inc"); + +class ZotOAuth1DataStore extends OAuth1DataStore { + + function gen_token(){ return md5(base64_encode(pack('N6', mt_rand(), mt_rand(), mt_rand(), mt_rand(), mt_rand(), uniqid()))); - } + } - function lookup_consumer($consumer_key) { - logger(__function__.":".$consumer_key); -// echo "<pre>"; var_dump($consumer_key); killme(); + function lookup_consumer($consumer_key) { + logger('consumer_key: ' . $consumer_key, LOGGER_DEBUG); $r = q("SELECT client_id, pw, redirect_uri FROM clients WHERE client_id = '%s'", dbesc($consumer_key) @@ -26,13 +28,14 @@ class FKOAuthDataStore extends OAuthDataStore { if($r) { get_app()->set_oauth_key($consumer_key); - return new OAuthConsumer($r[0]['client_id'],$r[0]['pw'],$r[0]['redirect_uri']); + return new OAuth1Consumer($r[0]['client_id'],$r[0]['pw'],$r[0]['redirect_uri']); } return null; - } + } - function lookup_token($consumer, $token_type, $token) { - logger(__function__.":".$consumer.", ". $token_type.", ".$token); + function lookup_token($consumer, $token_type, $token) { + + logger(__function__.":".$consumer.", ". $token_type.", ".$token, LOGGER_DEBUG); $r = q("SELECT id, secret, scope, expires, uid FROM tokens WHERE client_id = '%s' AND scope = '%s' AND id = '%s'", dbesc($consumer->key), @@ -41,17 +44,16 @@ class FKOAuthDataStore extends OAuthDataStore { ); if (count($r)){ - $ot=new OAuthToken($r[0]['id'],$r[0]['secret']); + $ot=new OAuth1Token($r[0]['id'],$r[0]['secret']); $ot->scope=$r[0]['scope']; $ot->expires = $r[0]['expires']; $ot->uid = $r[0]['uid']; return $ot; } return null; - } + } - function lookup_nonce($consumer, $token, $nonce, $timestamp) { -// echo __file__.":".__line__."<pre>"; var_dump($consumer,$key); killme(); + function lookup_nonce($consumer, $token, $nonce, $timestamp) { $r = q("SELECT id, secret FROM tokens WHERE client_id = '%s' AND id = '%s' AND expires = %d", dbesc($consumer->key), @@ -60,12 +62,14 @@ class FKOAuthDataStore extends OAuthDataStore { ); if (count($r)) - return new OAuthToken($r[0]['id'],$r[0]['secret']); + return new OAuth1Token($r[0]['id'],$r[0]['secret']); return null; - } + } + + function new_request_token($consumer, $callback = null) { + + logger(__function__.":".$consumer.", ". $callback, LOGGER_DEBUG); - function new_request_token($consumer, $callback = null) { - logger(__function__.":".$consumer.", ". $callback); $key = $this->gen_token(); $sec = $this->gen_token(); @@ -82,29 +86,31 @@ class FKOAuthDataStore extends OAuthDataStore { 'request', time()+intval(REQUEST_TOKEN_DURATION)); - if (!$r) return null; - return new OAuthToken($key,$sec); - } + if(! $r) + return null; + return new OAuth1Token($key,$sec); + } - function new_access_token($token, $consumer, $verifier = null) { - logger(__function__.":".$token.", ". $consumer.", ". $verifier); - - // return a new access token attached to this consumer - // for the user associated with this token if the request token - // is authorized - // should also invalidate the request token - - $ret=Null; + function new_access_token($token, $consumer, $verifier = null) { + + logger(__function__.":".$token.", ". $consumer.", ". $verifier, LOGGER_DEBUG); - // get user for this verifier - $uverifier = get_config("oauth", $verifier); - logger(__function__.":".$verifier.",".$uverifier); - if (is_null($verifier) || ($uverifier!==false)){ + // return a new access token attached to this consumer + // for the user associated with this token if the request token + // is authorized + // should also invalidate the request token + + $ret=Null; + + // get user for this verifier + $uverifier = get_config("oauth", $verifier); + logger(__function__.":".$verifier.",".$uverifier, LOGGER_DEBUG); + if (is_null($verifier) || ($uverifier!==false)) { - $key = $this->gen_token(); - $sec = $this->gen_token(); + $key = $this->gen_token(); + $sec = $this->gen_token(); - $r = q("INSERT INTO tokens (id, secret, client_id, scope, expires, uid) VALUES ('%s','%s','%s','%s', %d, %d)", + $r = q("INSERT INTO tokens (id, secret, client_id, scope, expires, uid) VALUES ('%s','%s','%s','%s', %d, %d)", dbesc($key), dbesc($sec), dbesc($consumer->key), @@ -112,81 +118,70 @@ class FKOAuthDataStore extends OAuthDataStore { time()+intval(ACCESS_TOKEN_DURATION), intval($uverifier)); - if ($r) - $ret = new OAuthToken($key,$sec); - } + if ($r) + $ret = new OAuth1Token($key,$sec); + } - q("DELETE FROM tokens WHERE id='%s'", $token->key); + q("DELETE FROM tokens WHERE id='%s'", $token->key); - if (!is_null($ret) && $uverifier!==false){ - del_config("oauth", $verifier); - /* $apps = get_pconfig($uverifier, "oauth", "apps"); - if ($apps===false) $apps=array(); - $apps[] = $consumer->key; - set_pconfig($uverifier, "oauth", "apps", $apps);*/ + if (!is_null($ret) && $uverifier!==false) { + del_config("oauth", $verifier); + + // $apps = get_pconfig($uverifier, "oauth", "apps"); + // if ($apps===false) $apps=array(); + // $apps[] = $consumer->key; + // set_pconfig($uverifier, "oauth", "apps", $apps); + } + return $ret; } - - return $ret; - - } } -class FKOAuth1 extends OAuthServer { +class ZotOAuth1 extends OAuth1Server { function __construct() { - parent::__construct(new FKOAuthDataStore()); - $this->add_signature_method(new OAuthSignatureMethod_PLAINTEXT()); - $this->add_signature_method(new OAuthSignatureMethod_HMAC_SHA1()); + parent::__construct(new ZotOAuth1DataStore()); + $this->add_signature_method(new OAuth1SignatureMethod_PLAINTEXT()); + $this->add_signature_method(new OAuth1SignatureMethod_HMAC_SHA1()); } function loginUser($uid){ - logger("RedOAuth1::loginUser $uid"); - $a = get_app(); + + logger("ZotOAuth1::loginUser $uid"); + $r = q("SELECT * FROM channel WHERE channel_id = %d LIMIT 1", intval($uid) ); if(count($r)){ $record = $r[0]; } else { - logger('FKOAuth1::loginUser failure: ' . print_r($_SERVER,true), LOGGER_DEBUG); - header('HTTP/1.0 401 Unauthorized'); - die('This api requires login'); + logger('ZotOAuth1::loginUser failure: ' . print_r($_SERVER,true), LOGGER_DEBUG); + header('HTTP/1.0 401 Unauthorized'); + echo('This api requires login'); + killme(); } $_SESSION['uid'] = $record['channel_id']; - $_SESSION['theme'] = $record['channel_theme']; - $_SESSION['account_id'] = $record['channel_account_id']; - $_SESSION['mobile_theme'] = get_pconfig($record['channel_id'], 'system', 'mobile_theme'); - $_SESSION['authenticated'] = 1; - $_SESSION['my_url'] = $a->get_baseurl() . '/channel/' . $record['channel_address']; $_SESSION['addr'] = $_SERVER['REMOTE_ADDR']; - $_SESSION['allow_api'] = true; + $x = q("select * from account where account_id = %d limit 1", intval($record['channel_account_id']) ); - if($x) - $a->account = $x[0]; - - change_channel($record['channel_id']); - - $a->channel = $record; - - if(strlen($a->channel['channel_timezone'])) { - date_default_timezone_set($a->channel['channel_timezone']); + if($x) { + require_once('include/security.php'); + authenticate_success($x[0],true,false,true,true); + $_SESSION['allow_api'] = true; } - -// q("UPDATE `user` SET `login_date` = '%s' WHERE `uid` = %d LIMIT 1", -// dbesc(datetime_convert()), -// intval($_SESSION['uid']) -// ); -// -// call_hooks('logged_in', $a->user); } } + /* + * + + not yet used + class FKOAuth2 extends OAuth2 { private function db_secret($client_secret){ diff --git a/include/photos.php b/include/photos.php index c7360a956..93511d2c0 100644 --- a/include/photos.php +++ b/include/photos.php @@ -292,17 +292,35 @@ function photo_upload($channel, $observer, $args) { $tag = (($r2) ? '[zmg=' . $width . 'x' . $height . ']' : '[zmg]'); } - $body = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo_hash . ']' + $author_link = '[zrl=' . z_root() . '/channel/' . $channel['channel_address'] . ']' . $channel['channel_name'] . '[/zrl]'; + + $photo_link = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo_hash . ']' . t('a new photo') . '[/zrl]'; + + $album_link = '[zrl=' . z_root() . '/photos/album/' . bin2hex($album) . ']' . $album . '[/zrl]'; + + $activity_format = sprintf(t('%1$s posted %2$s to %3$s','photo_upload'), $author_link, $photo_link, $album_link); + + $summary = $activity_format . "\n\n" . (($args['body']) ? $args['body'] . "\n\n" : ''); + + $obj_body = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo_hash . ']' . $tag . z_root() . "/photo/{$photo_hash}-{$scale}." . $ph->getExt() . '[/zmg]' . '[/zrl]'; // Create item object $object = array( - 'type' => ACTIVITY_OBJ_PHOTO, - 'title' => $title, - 'id' => rawurlencode(z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo_hash), - 'link' => $link, - 'bbcode' => $body + 'type' => ACTIVITY_OBJ_PHOTO, + 'title' => $title, + 'created' => $p['created'], + 'edited' => $p['edited'], + 'id' => rawurlencode(z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo_hash), + 'link' => $link, + 'body' => $obj_body + ); + + $target = array( + 'type' => ACTIVITY_OBJ_ALBUM, + 'title' => (($album) ? $album : '/'), + 'id' => rawurlencode(z_root() . '/photos/' . $channel['channel_address'] . '/album/' . bin2hex($album)) ); // Create item container @@ -314,9 +332,12 @@ function photo_upload($channel, $observer, $args) { if($item['mid'] === $item['parent_mid']) { - $item['body'] = (($object) ? $args['body'] : $body . "\r\n" . $args['body']); - $item['obj_type'] = (($object) ? ACTIVITY_OBJ_PHOTO : ''); - $item['object'] = (($object) ? json_encode($object) : ''); + $item['body'] = $args['body']; + $item['obj_type'] = ACTIVITY_OBJ_PHOTO; + $item['object'] = json_encode($object); + + $item['tgt_type'] = ACTIVITY_OBJ_ALBUM; + $item['target'] = json_encode($target); if($item['author_xchan'] === $channel['channel_hash']) { $item['sig'] = base64url_encode(rsa_sign($item['body'],$channel['channel_prvkey'])); @@ -370,14 +391,16 @@ function photo_upload($channel, $observer, $args) { $arr['deny_cid'] = $ac['deny_cid']; $arr['deny_gid'] = $ac['deny_gid']; $arr['verb'] = ACTIVITY_POST; - $arr['obj_type'] = (($object) ? ACTIVITY_OBJ_PHOTO : ''); - $arr['object'] = (($object) ? json_encode($object) : ''); + $arr['obj_type'] = ACTIVITY_OBJ_PHOTO; + $arr['object'] = json_encode($object); + $arr['tgt_type'] = ACTIVITY_OBJ_ALBUM; + $arr['target'] = json_encode($target); $arr['item_wall'] = 1; $arr['item_origin'] = 1; $arr['item_thread_top'] = 1; $arr['item_private'] = intval($acl->is_private()); $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid']; - $arr['body'] = (($object) ? $args['body'] : $body . "\r\n" . $args['body']); + $arr['body'] = $summary; // this one is tricky because the item and the photo have the same permissions, those of the photo. @@ -402,7 +425,7 @@ function photo_upload($channel, $observer, $args) { $ret['success'] = true; $ret['item'] = $arr; - $ret['body'] = $body; + $ret['body'] = $obj_body; $ret['resource_id'] = $photo_hash; $ret['photoitem_id'] = $item_id; diff --git a/include/plugin.php b/include/plugin.php index 8749f3fbf..4a35a0170 100755 --- a/include/plugin.php +++ b/include/plugin.php @@ -495,6 +495,15 @@ function format_css_if_exists($source) { return '<link rel="stylesheet" href="' . script_path() . '/' . $path . '" type="text/css" media="' . $source[1] . '">' . "\r\n"; } +/* + * This basically calculates the baseurl. We have other functions to do that, but + * there was an issue with script paths and mixed-content whose details are arcane + * and perhaps lost in the message archives. The short answer is that we're ignoring + * the URL which we are "supposed" to use, and generating script paths relative to + * the URL which we are currently using; in order to ensure they are found and aren't + * blocked due to mixed content issues. + */ + function script_path() { if(x($_SERVER,'HTTPS') && $_SERVER['HTTPS']) $scheme = 'https'; @@ -616,3 +625,24 @@ function get_markup_template($s, $root = '') { $template = $t->get_markup_template($s, $root); return $template; } + +// return the standardised version. Since we can't easily compare +// before the STD_VERSION definition was applied, we have to treat +// all prior release versions the same. You can dig through them +// with other means (such as RED_VERSION) if necessary. + +function get_std_version() { + if(defined('STD_VERSION')) + return STD_VERSION; + return '0.0.0'; +} + + +function folder_exists($folder) +{ + // Get canonicalized absolute pathname + $path = realpath($folder); + + // If it exist, check if it's a directory + return (($path !== false) && is_dir($path)) ? $path : false; +}
\ No newline at end of file diff --git a/include/queue.php b/include/queue.php index 71ac50c83..8a3b2aa58 100644 --- a/include/queue.php +++ b/include/queue.php @@ -18,11 +18,8 @@ function queue_run($argv, $argc){ else $queue_id = 0; - $deadguys = array(); - logger('queue: start'); - // delete all queue items more than 3 days old // but first mark these sites dead if we haven't heard from them in a month @@ -88,59 +85,7 @@ function queue_run($argv, $argc){ return; foreach($r as $rr) { - - $dresult = null; - - if(in_array($rr['outq_posturl'],$deadguys)) - continue; - - $base = ''; - $h = parse_url($rr['outq_posturl']); - if($h) - $base = $h['scheme'] . '://' . $h['host'] . (($h['port']) ? ':' . $h['port'] : ''); - - if($rr['outq_driver'] === 'post') { - $result = z_post_url($rr['outq_posturl'],$rr['outq_msg']); - if($result['success'] && $result['return_code'] < 300) { - logger('queue: queue post success to ' . $rr['outq_posturl'], LOGGER_DEBUG); - if($base) { - q("update site set site_update = '%s', site_dead = 0 where site_url = '%s' ", - dbesc(datetime_convert()), - dbesc($base) - ); - } - q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s' limit 1", - dbesc('accepted for delivery'), - dbesc(datetime_convert()), - dbesc($rr['outq_hash']) - ); - $y = q("delete from outq where outq_hash = '%s'", - dbesc($rr['outq_hash']) - ); - } - else { - logger('queue: queue post returned ' . $result['return_code'] . ' from ' . $rr['outq_posturl'],LOGGER_DEBUG); - $y = q("update outq set outq_updated = '%s', outq_priority = outq_priority + 10 where outq_hash = '%s'", - dbesc(datetime_convert()), - dbesc($rr['outq_hash']) - ); - $deadguys[] = $rr['outq_posturl']; - } - continue; - } - $result = zot_zot($rr['outq_posturl'],$rr['outq_notify']); - if($result['success']) { - logger('queue: deliver zot success to ' . $rr['outq_posturl'], LOGGER_DEBUG); - zot_process_response($rr['outq_posturl'],$result, $rr); - } - else { - $deadguys[] = $rr['outq_posturl']; - logger('queue: deliver zot returned ' . $result['return_code'] . ' from ' . $rr['outq_posturl'],LOGGER_DEBUG); - $y = q("update outq set outq_updated = '%s', outq_priority = outq_priority + 10 where outq_hash = '%s'", - dbesc(datetime_convert()), - dbesc($rr['outq_hash']) - ); - } + queue_deliver($rr); } } diff --git a/include/queue_fn.php b/include/queue_fn.php index 22580bc48..1e53d7488 100644 --- a/include/queue_fn.php +++ b/include/queue_fn.php @@ -1,18 +1,145 @@ <?php /** @file */ -function update_queue_time($id) { - logger('queue: requeue item ' . $id); - q("UPDATE outq SET outq_updated = '%s' WHERE outq_hash = '%s'", +function update_queue_item($id, $add_priority = 0) { + logger('queue: requeue item ' . $id,LOGGER_DEBUG); + q("UPDATE outq SET outq_updated = '%s', outq_priority = outq_priority + %d WHERE outq_hash = '%s'", dbesc(datetime_convert()), + intval($add_priority), dbesc($id) ); } -function remove_queue_item($id) { - logger('queue: remove queue item ' . $id); - q("DELETE FROM outq WHERE hash = '%s'", +function remove_queue_item($id,$channel_id = 0) { + logger('queue: remove queue item ' . $id,LOGGER_DEBUG); + $sql_extra = (($channel_id) ? " and outq_channel = " . intval($channel_id) . " " : ''); + + q("DELETE FROM outq WHERE outq_hash = '%s' $sql_extra", dbesc($id) ); } +function remove_queue_by_posturl($posturl) { + logger('queue: remove queue posturl ' . $posturl,LOGGER_DEBUG); + + q("DELETE FROM outq WHERE outq_posturl = '%s' ", + dbesc($posturl) + ); +} + + + +function queue_set_delivered($id,$channel = 0) { + logger('queue: set delivered ' . $id,LOGGER_DEBUG); + $sql_extra = (($channel_id) ? " and outq_channel = " . intval($channel_id) . " " : ''); + + q("update outq set outq_delivered = 1, outq_updated = '%s' where outq_hash = '%s' $sql_extra ", + dbesc(datetime_convert()), + dbesc($id) + ); +} + + + +function queue_insert($arr) { + + $x = q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_priority, + outq_created, outq_updated, outq_notify, outq_msg ) + values ( '%s', %d, %d, '%s', '%s', %d, %d, '%s', '%s', '%s', '%s' )", + dbesc($arr['hash']), + intval($arr['account_id']), + intval($arr['channel_id']), + dbesc(($arr['driver']) ? $arr['driver'] : 'zot'), + dbesc($arr['posturl']), + intval(1), + intval(($arr['priority']) ? $arr['priority'] : 0), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + dbesc($arr['notify']), + dbesc(($arr['msg']) ? $arr['msg'] : '') + ); + return $x; + +} + + + +function queue_deliver($outq, $immediate = false) { + + $base = null; + $h = parse_url($outq['outq_posturl']); + if($h) + $base = $h['scheme'] . '://' . $h['host'] . (($h['port']) ? ':' . $h['port'] : ''); + + if(($base) && ($base !== z_root()) && ($immediate)) { + $y = q("select site_update, site_dead from site where site_url = '%s' ", + dbesc($base) + ); + if($y) { + if(intval($y[0]['site_dead'])) { + remove_queue_by_posturl($outq['outq_posturl']); + logger('dead site ignored ' . $base); + return; + } + if($y[0]['site_update'] < datetime_convert('UTC','UTC','now - 1 month')) { + update_queue_item($outq['outq_hash'],10); + logger('immediate delivery deferred for site ' . $base); + return; + } + } + else { + // zot sites should all have a site record, unless they've been dead for as long as + // your site has existed. Since we don't know for sure what these sites are, + // call them unknown + + q("insert into site (site_url, site_update, site_dead, site_type) values ('%s','%s',0,%d) ", + dbesc($base), + dbesc(datetime_convert()), + intval(($outq['outq_driver'] === 'post') ? SITE_TYPE_NOTZOT : SITE_TYPE_UNKNOWN) + ); + } + } + + // "post" queue driver - used for diaspora and friendica-over-diaspora communications. + + if($outq['outq_driver'] === 'post') { + $result = z_post_url($outq['outq_posturl'],$outq['outq_msg']); + if($result['success'] && $result['return_code'] < 300) { + logger('deliver: queue post success to ' . $outq['outq_posturl'], LOGGER_DEBUG); + if($base) { + q("update site set site_update = '%s', site_dead = 0 where site_url = '%s' ", + dbesc(datetime_convert()), + dbesc($base) + ); + } + q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s' limit 1", + dbesc('accepted for delivery'), + dbesc(datetime_convert()), + dbesc($outq['outq_hash']) + ); + remove_queue_item($outq['outq_hash']); + } + else { + logger('deliver: queue post returned ' . $result['return_code'] + . ' from ' . $outq['outq_posturl'],LOGGER_DEBUG); + update_queue_item($argv[$x]); + } + return; + } + + // normal zot delivery + + logger('deliver: dest: ' . $outq['outq_posturl'], LOGGER_DEBUG); + $result = zot_zot($outq['outq_posturl'],$outq['outq_notify']); + if($result['success']) { + logger('deliver: remote zot delivery succeeded to ' . $outq['outq_posturl']); + zot_process_response($outq['outq_posturl'],$result, $outq); + } + else { + logger('deliver: remote zot delivery failed to ' . $outq['outq_posturl']); + logger('deliver: remote zot delivery fail data: ' . print_r($result,true), LOGGER_DATA); + update_queue_item($outq['outq_hash'],10); + } + return; +} + diff --git a/include/ratenotif.php b/include/ratenotif.php index 63fd7c2ee..e94f30247 100644 --- a/include/ratenotif.php +++ b/include/ratenotif.php @@ -82,18 +82,14 @@ function ratenotif_run($argv, $argc){ $hash = random_string(); $n = zot_build_packet($channel,'notify',null,null,$hash); - q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", - dbesc($hash), - intval($channel['channel_account_id']), - intval($channel['channel_id']), - dbesc('zot'), - dbesc($h . '/post'), - intval(1), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc($n), - dbesc(json_encode($encoded_item)) - ); + queue_insert(array( + 'hash' => $hash, + 'account_id' => $channel['channel_account_id'], + 'channel_id' => $channel['channel_id'], + 'posturl' => $h . '/post', + 'notify' => $n, + 'msg' => json_encode($encoded_item) + )); $deliver[] = $hash; diff --git a/include/security.php b/include/security.php index 9a25d9e0e..d4ebe0024 100644 --- a/include/security.php +++ b/include/security.php @@ -93,6 +93,7 @@ function change_channel($change_channel) { $ret = false; if($change_channel) { + $r = q("select channel.*, xchan.* from channel left join xchan on channel.channel_hash = xchan.xchan_hash where channel_id = %d and channel_account_id = %d and channel_removed = 0 limit 1", intval($change_channel), intval(get_account_id()) @@ -136,14 +137,14 @@ function change_channel($change_channel) { } /** - * @brief Creates an addiontal SQL where statement to check permissions. + * @brief Creates an additional SQL where statement to check permissions. * * @param int $owner_id - * @param bool $remote_verified default false, not used at all - * @param string $groups this param is not used at all + * @param bool $remote_observer - if unset use current observer * * @return string additional SQL where statement */ + function permissions_sql($owner_id, $remote_observer = null) { $local_channel = local_channel(); @@ -208,8 +209,7 @@ function permissions_sql($owner_id, $remote_observer = null) { * @brief Creates an addiontal SQL where statement to check permissions for an item. * * @param int $owner_id - * @param bool $remote_verified default false, not used at all - * @param string $groups this param is not used at all + * @param bool $remote_observer, use current observer if unset * * @return string additional SQL where statement */ @@ -400,11 +400,9 @@ function check_form_security_token_ForbiddenOnErr($typename = '', $formname = 'f } -// Returns an array of group id's this contact is a member of. -// This array will only contain group id's related to the uid of this -// DFRN contact. They are *not* neccessarily unique across the entire site. +// Returns an array of group hash id's on this entire site (across all channels) that this connection is a member of. +// var $contact_id = xchan_hash of connection -if(! function_exists('init_groups_visitor')) { function init_groups_visitor($contact_id) { $groups = array(); $r = q("SELECT hash FROM `groups` left join group_member on groups.id = group_member.gid WHERE xchan = '%s' ", @@ -415,7 +413,7 @@ function init_groups_visitor($contact_id) { $groups[] = $rr['hash']; } return $groups; -}} +} diff --git a/include/taxonomy.php b/include/taxonomy.php index b396d53f1..0bf89a7c1 100644 --- a/include/taxonomy.php +++ b/include/taxonomy.php @@ -117,6 +117,8 @@ function tagadelic($uid, $count = 0, $authors = '', $owner = '', $flags = 0, $re if(! perm_is_allowed($uid,get_observer_hash(),'view_stream')) return array(); + + $item_normal = item_normal(); $sql_options = item_permissions_sql($uid); $count = intval($count); @@ -142,7 +144,7 @@ function tagadelic($uid, $count = 0, $authors = '', $owner = '', $flags = 0, $re $r = q("select term, count(term) as total from term left join item on term.oid = item.id where term.uid = %d and term.type = %d and otype = %d and item_type = %d and item_private = 0 - $sql_options + $sql_options $item_normal group by term order by total desc %s", intval($uid), intval($type), diff --git a/include/text.php b/include/text.php index eb9171b40..dd52b16b6 100644 --- a/include/text.php +++ b/include/text.php @@ -5,6 +5,7 @@ require_once("include/template_processor.php"); require_once("include/smarty.php"); +require_once("include/bbcode.php"); // random string, there are 86 characters max in text mode, 128 for hex // output is urlsafe @@ -1380,25 +1381,49 @@ function generate_named_map($location) { return (($arr['html']) ? $arr['html'] : $location); } +function format_event($jobject) { + $event = array(); + $object = json_decode($jobject,true); + + //ensure compatibility with older items - this check can be removed at a later point + if(array_key_exists('description', $object)) { + + $bd_format = t('l F d, Y \@ g:i A'); // Friday January 18, 2011 @ 8:01 AM + + $event['header'] = replace_macros(get_markup_template('event_item_header.tpl'),array( + '$title' => bbcode($object['title']), + '$dtstart_label' => t('Starts:'), + '$dtstart_title' => datetime_convert('UTC', 'UTC', $object['start'], (($object['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )), + '$dtstart_dt' => (($object['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(), $object['start'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $object['start'] , $bd_format))), + '$finish' => (($object['nofinish']) ? false : true), + '$dtend_label' => t('Finishes:'), + '$dtend_title' => datetime_convert('UTC','UTC',$object['finish'], (($object['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )), + '$dtend_dt' => (($object['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(), $object['finish'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $object['finish'] , $bd_format ))) + )); + + $event['content'] = replace_macros(get_markup_template('event_item_content.tpl'),array( + '$description' => bbcode($object['description']), + '$location_label' => t('Location:'), + '$location' => bbcode($object['location']) + )); + + } + + return $event; +} function prepare_body(&$item,$attach = false) { require_once('include/identity.php'); -// if($item['html']) { -// $s = bb_observer($item['html']); -// } -// else { - call_hooks('prepare_body_init', $item); -// unobscure($item); - $s = prepare_text($item['body'],$item['mimetype'], false); -// } + call_hooks('prepare_body_init', $item); $photo = ''; - $is_photo = (($item['obj_type'] === ACTIVITY_OBJ_PHOTO) ? true : false); + $is_photo = ((($item['verb'] === ACTIVITY_POST) && ($item['obj_type'] === ACTIVITY_OBJ_PHOTO)) ? true : false); if($is_photo) { + $object = json_decode($item['object'],true); // if original photo width is <= 640px prepend it to item body @@ -1413,9 +1438,14 @@ function prepare_body(&$item,$attach = false) { } } + $s = prepare_text($item['body'],$item['mimetype'], false); + + $event = (($item['obj_type'] === ACTIVITY_OBJ_EVENT) ? format_event($item['object']) : false); + $prep_arr = array( 'item' => $item, - 'html' => $s, + 'html' => $event ? $event['content'] : $s, + 'event' => $event['header'], 'photo' => $photo ); @@ -1423,6 +1453,7 @@ function prepare_body(&$item,$attach = false) { $s = $prep_arr['html']; $photo = $prep_arr['photo']; + $event = $prep_arr['event']; // q("update item set html = '%s' where id = %d", // dbesc($s), @@ -1489,6 +1520,7 @@ function prepare_body(&$item,$attach = false) { 'item' => $item, 'photo' => $photo, 'html' => $s, + 'event' => $event, 'categories' => $categories, 'folders' => $filer, 'tags' => $tags, @@ -1566,6 +1598,16 @@ function prepare_text($text, $content_type = 'text/bbcode', $cache = false) { } +function create_export_photo_body(&$item) { + if(($item['verb'] === ACTIVITY_POST) && ($item['obj_type'] === ACTIVITY_OBJ_PHOTO)) { + $j = json_decode($item['object'],true); + if($j) { + $item['body'] .= "\n\n" . (($j['body']) ? $j['body'] : $j['bbcode']); + $item['sig'] = ''; + } + } +} + /** * zidify_callback() and zidify_links() work together to turn any HTML a tags with class="zrl" into zid links * These will typically be generated by a bbcode '[zrl]' tag. This is done inside prepare_text() rather than bbcode() diff --git a/include/widgets.php b/include/widgets.php index a3f7444ec..4b14d6c94 100644 --- a/include/widgets.php +++ b/include/widgets.php @@ -666,7 +666,7 @@ function widget_eventsmenu($arr) { if (! local_channel()) return; - return replace_macros(get_markup_template('events_side.tpl'), array( + return replace_macros(get_markup_template('events_menu_side.tpl'), array( '$title' => t('Events Menu'), '$day' => t('Day View'), '$week' => t('Week View'), @@ -677,6 +677,18 @@ function widget_eventsmenu($arr) { )); } +function widget_eventstools($arr) { + if (! local_channel()) + return; + + return replace_macros(get_markup_template('events_tools_side.tpl'), array( + '$title' => t('Events Tools'), + '$export' => t('Export Calendar'), + '$import' => t('Import Calendar'), + '$submit' => t('Submit') + )); +} + function widget_design_tools($arr) { $a = get_app(); @@ -1136,7 +1148,7 @@ function widget_forums($arr) { foreach($r1 as $rr) { if($unseen && (! intval($rr['unseen']))) continue; - $o .= '<li><span class="pull-right">' . ((intval($rr['unseen'])) ? intval($rr['unseen']) : '') . '</span><a href="network?f=&pf=1&cid=' . $rr['abook_id'] . '" ><img src="' . $rr['xchan_photo_s'] . '" style="width: 16px; height: 16px;" /> ' . $rr['xchan_name'] . '</a></li>'; + $o .= '<li><a href="network?f=&pf=1&cid=' . $rr['abook_id'] . '" ><span class="badge pull-right">' . ((intval($rr['unseen'])) ? intval($rr['unseen']) : '') . '</span><img src="' . $rr['xchan_photo_s'] . '" style="width: 16px; height: 16px;" /> ' . $rr['xchan_name'] . '</a></li>'; } $o .= '</ul></div>'; } @@ -1147,6 +1159,8 @@ function widget_forums($arr) { function widget_tasklist($arr) { + if (! local_channel()) + return; require_once('include/event.php'); $o .= '<script>var tasksShowAll = 0; $(document).ready(function() { tasksFetch(); $("#tasklist-new-form").submit(function(event) { event.preventDefault(); $.post( "tasks/new", $("#tasklist-new-form").serialize(), function(data) { tasksFetch(); $("#tasklist-new-summary").val(""); } ); return false; } )});</script>'; @@ -1285,7 +1299,6 @@ function widget_album($args) { //edit album name $album_edit = null; - $photos = array(); if($r) { $twist = 'rotright'; @@ -1324,6 +1337,7 @@ function widget_album($args) { $o .= replace_macros($tpl, array( '$photos' => $photos, '$album' => (($title) ? $title : $album), + '$album_id' => rand(), '$album_edit' => array(t('Edit Album'), $album_edit), '$can_post' => false, '$upload' => array(t('Upload'), z_root() . '/photos/' . get_app()->profile['channel_address'] . '/upload/' . bin2hex($album)), diff --git a/include/zot.php b/include/zot.php index 2366c1d2d..922637bc1 100644 --- a/include/zot.php +++ b/include/zot.php @@ -12,6 +12,7 @@ require_once('include/crypto.php'); require_once('include/items.php'); require_once('include/hubloc.php'); require_once('include/DReport.php'); +require_once('include/queue_fn.php'); /** @@ -554,18 +555,8 @@ function zot_gethub($arr,$multiple = false) { if($arr['guid'] && $arr['guid_sig'] && $arr['url'] && $arr['url_sig']) { - $blacklisted = false; - $bl1 = get_config('system','blacklisted_sites'); - if(is_array($bl1) && $bl1) { - foreach($bl1 as $bl) { - if($bl && strpos($arr['url'],$bl) !== false) { - $blacklisted = true; - break; - } - } - } - if($blacklisted) { - logger('zot_gethub: blacklisted site: ' . $arr['url']); + if(! check_siteallowed($arr['url'])) { + logger('blacklisted site: ' . $arr['url']); return null; } @@ -1007,7 +998,9 @@ function zot_process_response($hub, $arr, $outq) { } } - q("delete from dreport where dreport_queue = '%s' limit 1", + // we have a more descriptive delivery report, so discard the per hub 'queued' report. + + q("delete from dreport where dreport_queue = '%s' ", dbesc($outq['outq_hash']) ); @@ -1021,18 +1014,8 @@ function zot_process_response($hub, $arr, $outq) { // synchronous message types are handled immediately // async messages remain in the queue until processed. - if (intval($outq['outq_async'])) { - q("update outq set outq_delivered = 1, outq_updated = '%s' where outq_hash = '%s' and outq_channel = %d", - dbesc(datetime_convert()), - dbesc($outq['outq_hash']), - intval($outq['outq_channel']) - ); - } else { - q("delete from outq where outq_hash = '%s' and outq_channel = %d", - dbesc($outq['outq_hash']), - intval($outq['outq_channel']) - ); - } + if(intval($outq['outq_async'])) + queue_set_delivered($outq['outq_hash'],$outq['outq_channel']); logger('zot_process_response: ' . print_r($x,true), LOGGER_DEBUG); } @@ -1246,6 +1229,10 @@ function zot_import($arr, $sender_url) { $no_dups = array(); if($deliveries) { foreach($deliveries as $d) { + if(! is_array($d)) { + logger('Delivery hash array is not an array: ' . print_r($d,true)); + continue; + } if(! in_array($d['hash'],$no_dups)) $no_dups[] = $d['hash']; } @@ -1617,6 +1604,14 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $ $channel = $r[0]; $DR->addto_recipient($channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>'); + /* blacklisted channels get a permission denied, no special message to tip them off */ + + if(! check_channelallowed($sender['hash'])) { + $DR->update('permission denied'); + $result[] = $DR->get(); + continue; + } + /** * @FIXME: Somehow we need to block normal message delivery from our clones, as the delivered * message doesn't have ACL information in it as the cloned copy does. That copy @@ -2088,6 +2083,14 @@ function process_mail_delivery($sender, $arr, $deliveries) { $channel = $r[0]; $DR->addto_recipient($channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>'); + /* blacklisted channels get a permission denied, no special message to tip them off */ + + if(! check_channelallowed($sender['hash'])) { + $DR->update('permission denied'); + $result[] = $DR->get(); + continue; + } + if(! perm_is_allowed($channel['channel_id'],$sender['hash'],'post_mail')) { logger("permission denied for mail delivery {$channel['channel_id']}"); $DR->update('permission denied'); @@ -2964,24 +2967,19 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) { $interval = ((get_config('system','delivery_interval') !== false) ? intval(get_config('system','delivery_interval')) : 2 ); - logger('build_sync_packet: packet: ' . print_r($info,true), LOGGER_DATA); foreach($synchubs as $hub) { $hash = random_string(); $n = zot_build_packet($channel,'notify',$env_recips,$hub['hubloc_sitekey'],$hash); - q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", - dbesc($hash), - intval($channel['channel_account']), - intval($channel['channel_id']), - dbesc('zot'), - dbesc($hub['hubloc_callback']), - intval(1), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc($n), - dbesc(json_encode($info)) - ); + queue_insert(array( + 'hash' => $hash, + 'account_id' => $channel['channel_account_id'], + 'channel_id' => $channel['channel_id'], + 'posturl' => $hub['hubloc_callback'], + 'notify' => $n, + 'msg' => json_encode($info) + )); proc_run('php', 'include/deliver.php', $hash); if($interval) @@ -3484,13 +3482,13 @@ function import_author_zot($x) { * @param array $data * @return array */ -function zot_process_message_request($data) { +function zot_reply_message_request($data) { $ret = array('success' => false); if (! $data['message_id']) { $ret['message'] = 'no message_id'; logger('no message_id'); - return $ret; + json_return_and_die($ret); } $sender = $data['sender']; @@ -3508,7 +3506,7 @@ function zot_process_message_request($data) { if (! $c) { logger('recipient channel not found.'); $ret['message'] .= 'recipient not found.' . EOL; - return $ret; + json_return_and_die($ret); } /* @@ -3520,13 +3518,13 @@ function zot_process_message_request($data) { if ($messages) { $env_recips = null; - $r = q("select * from hubloc where hubloc_hash = '%s' and not hubloc_error and not hubloc_deleted + $r = q("select * from hubloc where hubloc_hash = '%s' and hubloc_error = 0 and hubloc_deleted = 0 group by hubloc_sitekey", dbesc($sender_hash) ); if (! $r) { logger('no hubs'); - return $ret; + json_return_and_die($ret); } $hubs = $r; @@ -3544,20 +3542,15 @@ function zot_process_message_request($data) { */ $n = zot_build_packet($c[0],'notify',$env_recips,(($private) ? $hub['hubloc_sitekey'] : null),$hash,array('message_id' => $data['message_id'])); - q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, - outq_created, outq_updated, outq_notify, outq_msg ) - values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", - dbesc($hash), - intval($c[0]['channel_account_id']), - intval($c[0]['channel_id']), - dbesc('zot'), - dbesc($hub['hubloc_callback']), - intval(1), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc($n), - dbesc($data_packet) - ); + + queue_insert(array( + 'hash' => $hash, + 'account_id' => $c[0]['channel_account_id'], + 'channel_id' => $c[0]['channel_id'], + 'posturl' => $hub['hubloc_callback'], + 'notify' => $n, + 'msg' => $data_packet + )); /* * invoke delivery to send out the notify packet @@ -3567,8 +3560,7 @@ function zot_process_message_request($data) { } } $ret['success'] = true; - - return $ret; + json_return_and_die($ret); } @@ -3789,6 +3781,7 @@ function zotinfo($arr) { $ret['site'] = array(); $ret['site']['url'] = z_root(); $ret['site']['url_sig'] = base64url_encode(rsa_sign(z_root(),$e['channel_prvkey'])); + $ret['site']['zot_auth'] = z_root() . '/magic'; $dirmode = get_config('system','directory_mode'); if(($dirmode === false) || ($dirmode == DIRECTORY_MODE_NORMAL)) @@ -3951,9 +3944,6 @@ function delivery_report_is_storable($dr) { return false; - - - // is the recipient one of our connections, or do we want to store every report? $r = explode(' ', $dr['recipient']); @@ -3982,3 +3972,420 @@ function delivery_report_is_storable($dr) { } + +function update_hub_connected($hub,$sitekey = '') { + + if($sitekey) { + + /* + * This hub has now been proven to be valid. + * Any hub with the same URL and a different sitekey cannot be valid. + * Get rid of them (mark them deleted). There's a good chance they were re-installs. + */ + + q("update hubloc set hubloc_deleted = 1, hubloc_error = 1 where hubloc_url = '%s' and hubloc_sitekey != '%s' ", + dbesc($hub['hubloc_url']), + dbesc($sitekey) + ); + + } + else { + $sitekey = $hub['sitekey']; + } + + // $sender['sitekey'] is a new addition to the protcol to distinguish + // hublocs coming from re-installed sites. Older sites will not provide + // this field and we have to still mark them valid, since we can't tell + // if this hubloc has the same sitekey as the packet we received. + + + // Update our DB to show when we last communicated successfully with this hub + // This will allow us to prune dead hubs from using up resources + + $r = q("update hubloc set hubloc_connected = '%s' where hubloc_id = %d and hubloc_sitekey = '%s' ", + dbesc(datetime_convert()), + intval($hub['hubloc_id']), + dbesc($sitekey) + ); + + // a dead hub came back to life - reset any tombstones we might have + + if(intval($hub['hubloc_error'])) { + q("update hubloc set hubloc_error = 0 where hubloc_id = %d and hubloc_sitekey = '%s' ", + intval($hub['hubloc_id']), + dbesc($sitekey) + ); + if(intval($r[0]['hubloc_orphancheck'])) { + q("update hubloc set hubloc_orhpancheck = 0 where hubloc_id = %d and hubloc_sitekey = '%s' ", + intval($hub['hubloc_id']), + dbesc($sitekey) + ); + } + q("update xchan set xchan_orphan = 0 where xchan_orphan = 1 and xchan_hash = '%s'", + dbesc($hub['hubloc_hash']) + ); + } + + return $hub['hubloc_url']; +} + + +function zot_reply_ping() { + + $ret = array('success'=> false); + + // Useful to get a health check on a remote site. + // This will let us know if any important communication details + // that we may have stored are no longer valid, regardless of xchan details. + logger('POST: got ping send pong now back: ' . z_root() , LOGGER_DEBUG ); + + $ret['success'] = true; + $ret['site'] = array(); + $ret['site']['url'] = z_root(); + $ret['site']['url_sig'] = base64url_encode(rsa_sign(z_root(),get_config('system','prvkey'))); + $ret['site']['sitekey'] = get_config('system','pubkey'); + json_return_and_die($ret); +} + +function zot_reply_pickup($data) { + + $ret = array('success'=> false); + + /* + * The 'pickup' message arrives with a tracking ID which is associated with a particular outq_hash + * First verify that that the returned signatures verify, then check that we have an outbound queue item + * with the correct hash. + * If everything verifies, find any/all outbound messages in the queue for this hubloc and send them back + */ + + if((! $data['secret']) || (! $data['secret_sig'])) { + $ret['message'] = 'no verification signature'; + logger('mod_zot: pickup: ' . $ret['message'], LOGGER_DEBUG); + json_return_and_die($ret); + } + + $r = q("select distinct hubloc_sitekey from hubloc where hubloc_url = '%s' and hubloc_callback = '%s' and hubloc_sitekey != '' group by hubloc_sitekey ", + dbesc($data['url']), + dbesc($data['callback']) + ); + if(! $r) { + $ret['message'] = 'site not found'; + logger('mod_zot: pickup: ' . $ret['message']); + json_return_and_die($ret); + } + + foreach ($r as $hubsite) { + + // verify the url_sig + // If the server was re-installed at some point, there could be multiple hubs with the same url and callback. + // Only one will have a valid key. + + $forgery = true; + $secret_fail = true; + + $sitekey = $hubsite['hubloc_sitekey']; + + logger('mod_zot: Checking sitekey: ' . $sitekey, LOGGER_DATA); + + if(rsa_verify($data['callback'],base64url_decode($data['callback_sig']),$sitekey)) { + $forgery = false; + } + if(rsa_verify($data['secret'],base64url_decode($data['secret_sig']),$sitekey)) { + $secret_fail = false; + } + if((! $forgery) && (! $secret_fail)) + break; + } + + if($forgery) { + $ret['message'] = 'possible site forgery'; + logger('mod_zot: pickup: ' . $ret['message']); + json_return_and_die($ret); + } + + if($secret_fail) { + $ret['message'] = 'secret validation failed'; + logger('mod_zot: pickup: ' . $ret['message']); + json_return_and_die($ret); + } + + /* + * If we made it to here, the signatures verify, but we still don't know if the tracking ID is valid. + * It wouldn't be an error if the tracking ID isn't found, because we may have sent this particular + * queue item with another pickup (after the tracking ID for the other pickup was verified). + */ + + $r = q("select outq_posturl from outq where outq_hash = '%s' and outq_posturl = '%s' limit 1", + dbesc($data['secret']), + dbesc($data['callback']) + ); + if(! $r) { + $ret['message'] = 'nothing to pick up'; + logger('mod_zot: pickup: ' . $ret['message']); + json_return_and_die($ret); + } + + /* + * Everything is good if we made it here, so find all messages that are going to this location + * and send them all. + */ + + $r = q("select * from outq where outq_posturl = '%s'", + dbesc($data['callback']) + ); + if($r) { + logger('mod_zot: successful pickup message received from ' . $data['callback'] . ' ' . count($r) . ' message(s) picked up', LOGGER_DEBUG); + + $ret['success'] = true; + $ret['pickup'] = array(); + foreach($r as $rr) { + if($rr['outq_msg']) { + $x = json_decode($rr['outq_msg'],true); + + if(! $x) + continue; + + if(is_array($x) && array_key_exists('message_list',$x)) { + foreach($x['message_list'] as $xx) { + $ret['pickup'][] = array('notify' => json_decode($rr['outq_notify'],true),'message' => $xx); + } + } + else + $ret['pickup'][] = array('notify' => json_decode($rr['outq_notify'],true),'message' => $x); + + remove_queue_item($rr['outq_hash']); + } + } + } + + $encrypted = crypto_encapsulate(json_encode($ret),$sitekey); + json_return_and_die($encrypted); + + /* pickup: end */ +} + + + +function zot_reply_auth_check($data,$encrypted_packet) { + + $ret = array('success' => false); + + /* + * Requestor visits /magic/?dest=somewhere on their own site with a browser + * magic redirects them to $destsite/post [with auth args....] + * $destsite sends an auth_check packet to originator site + * The auth_check packet is handled here by the originator's site + * - the browser session is still waiting + * inside $destsite/post for everything to verify + * If everything checks out we'll return a token to $destsite + * and then $destsite will verify the token, authenticate the browser + * session and then redirect to the original destination. + * If authentication fails, the redirection to the original destination + * will still take place but without authentication. + */ + logger('mod_zot: auth_check', LOGGER_DEBUG); + + if (! $encrypted_packet) { + logger('mod_zot: auth_check packet was not encrypted.'); + $ret['message'] .= 'no packet encryption' . EOL; + json_return_and_die($ret); + } + + $arr = $data['sender']; + $sender_hash = make_xchan_hash($arr['guid'],$arr['guid_sig']); + + // garbage collect any old unused notifications + + // This was and should be 10 minutes but my hosting provider has time lag between the DB and + // the web server. We should probably convert this to webserver time rather than DB time so + // that the different clocks won't affect it and allow us to keep the time short. + + q("delete from verify where type = 'auth' and created < %s - INTERVAL %s", + db_utcnow(), db_quoteinterval('30 MINUTE') + ); + + $y = q("select xchan_pubkey from xchan where xchan_hash = '%s' limit 1", + dbesc($sender_hash) + ); + + // We created a unique hash in mod/magic.php when we invoked remote auth, and stored it in + // the verify table. It is now coming back to us as 'secret' and is signed by a channel at the other end. + // First verify their signature. We will have obtained a zot-info packet from them as part of the sender + // verification. + + if ((! $y) || (! rsa_verify($data['secret'], base64url_decode($data['secret_sig']),$y[0]['xchan_pubkey']))) { + logger('mod_zot: auth_check: sender not found or secret_sig invalid.'); + $ret['message'] .= 'sender not found or sig invalid ' . print_r($y,true) . EOL; + json_return_and_die($ret); + } + + // There should be exactly one recipient, the original auth requestor + + $ret['message'] .= 'recipients ' . print_r($recipients,true) . EOL; + + if ($data['recipients']) { + + $arr = $data['recipients'][0]; + $recip_hash = make_xchan_hash($arr['guid'], $arr['guid_sig']); + $c = q("select channel_id, channel_account_id, channel_prvkey from channel where channel_hash = '%s' limit 1", + dbesc($recip_hash) + ); + if (! $c) { + logger('mod_zot: auth_check: recipient channel not found.'); + $ret['message'] .= 'recipient not found.' . EOL; + json_return_and_die($ret); + } + + $confirm = base64url_encode(rsa_sign($data['secret'] . $recip_hash,$c[0]['channel_prvkey'])); + + // This additionally checks for forged sites since we already stored the expected result in meta + // and we've already verified that this is them via zot_gethub() and that their key signed our token + + $z = q("select id from verify where channel = %d and type = 'auth' and token = '%s' and meta = '%s' limit 1", + intval($c[0]['channel_id']), + dbesc($data['secret']), + dbesc($data['sender']['url']) + ); + if (! $z) { + logger('mod_zot: auth_check: verification key not found.'); + $ret['message'] .= 'verification key not found' . EOL; + json_return_and_die($ret); + } + $r = q("delete from verify where id = %d", + intval($z[0]['id']) + ); + + $u = q("select account_service_class from account where account_id = %d limit 1", + intval($c[0]['channel_account_id']) + ); + + logger('mod_zot: auth_check: success', LOGGER_DEBUG); + $ret['success'] = true; + $ret['confirm'] = $confirm; + if ($u && $u[0]['account_service_class']) + $ret['service_class'] = $u[0]['account_service_class']; + + // Set "do not track" flag if this site or this channel's profile is restricted + // in some way + + if (intval(get_config('system','block_public'))) + $ret['DNT'] = true; + if (! perm_is_allowed($c[0]['channel_id'],'','view_profile')) + $ret['DNT'] = true; + if (get_pconfig($c[0]['channel_id'],'system','do_not_track')) + $ret['DNT'] = true; + if (get_pconfig($c[0]['channel_id'],'system','hide_online_status')) + $ret['DNT'] = true; + + json_return_and_die($ret); + } + json_return_and_die($ret); +} + + +function zot_reply_purge($sender,$recipients) { + + $ret = array('success' => false); + + if ($recipients) { + // basically this means "unfriend" + foreach ($recipients as $recip) { + $r = q("select channel.*,xchan.* from channel + left join xchan on channel_hash = xchan_hash + where channel_guid = '%s' and channel_guid_sig = '%s' limit 1", + dbesc($recip['guid']), + dbesc($recip['guid_sig']) + ); + if ($r) { + $r = q("select abook_id from abook where uid = %d and abook_xchan = '%s' limit 1", + intval($r[0]['channel_id']), + dbesc(make_xchan_hash($sender['guid'],$sender['guid_sig'])) + ); + if ($r) { + contact_remove($r[0]['channel_id'],$r[0]['abook_id']); + } + } + } + $ret['success'] = true; + } + else { + // Unfriend everybody - basically this means the channel has committed suicide + $arr = $sender; + $sender_hash = make_xchan_hash($arr['guid'],$arr['guid_sig']); + + require_once('include/Contact.php'); + remove_all_xchan_resources($sender_hash); + + $ret['success'] = true; + } + + json_return_and_die($ret); +} + + +function zot_reply_refresh($sender,$recipients) { + + $ret = array('success' => false); + + // remote channel info (such as permissions or photo or something) + // has been updated. Grab a fresh copy and sync it. + // The difference between refresh and force_refresh is that + // force_refresh unconditionally creates a directory update record, + // even if no changes were detected upon processing. + + if($recipients) { + + // This would be a permissions update, typically for one connection + + foreach ($recipients as $recip) { + $r = q("select channel.*,xchan.* from channel + left join xchan on channel_hash = xchan_hash + where channel_guid = '%s' and channel_guid_sig = '%s' limit 1", + dbesc($recip['guid']), + dbesc($recip['guid_sig']) + ); + + $x = zot_refresh(array( + 'xchan_guid' => $sender['guid'], + 'xchan_guid_sig' => $sender['guid_sig'], + 'hubloc_url' => $sender['url'] + ), $r[0], (($msgtype === 'force_refresh') ? true : false)); + } + } + else { + // system wide refresh + + $x = zot_refresh(array( + 'xchan_guid' => $sender['guid'], + 'xchan_guid_sig' => $sender['guid_sig'], + 'hubloc_url' => $sender['url'] + ), null, (($msgtype === 'force_refresh') ? true : false)); + } + + $ret['success'] = true; + json_return_and_die($ret); + +} + + +function zot_reply_notify($data) { + + $ret = array('success' => false); + + logger('notify received from ' . $data['sender']['url']); + + $async = get_config('system','queued_fetch'); + + if($async) { + // add to receive queue + // qreceive_add($data); + } + else { + $x = zot_fetch($data); + $ret['delivery_report'] = $x; + } + + $ret['success'] = true; + json_return_and_die($ret); + +}
\ No newline at end of file |