diff options
author | Haakon Meland Eriksen <haakon.eriksen@far.no> | 2014-06-24 19:34:36 +0200 |
---|---|---|
committer | Haakon Meland Eriksen <haakon.eriksen@far.no> | 2014-06-24 19:34:36 +0200 |
commit | b8dc9e855af2d30f33d0f90dc13d8cad0a7b3e70 (patch) | |
tree | 718df6305bcb82c8dcb4b287a7132422e748cdfb /mod | |
parent | c2d520f1be115fb3cb5da2a35eb10146cecee8aa (diff) | |
parent | a92fb0b04c3e6474ec48faf8e4cc65c382e89d66 (diff) | |
download | volse-hubzilla-b8dc9e855af2d30f33d0f90dc13d8cad0a7b3e70.tar.gz volse-hubzilla-b8dc9e855af2d30f33d0f90dc13d8cad0a7b3e70.tar.bz2 volse-hubzilla-b8dc9e855af2d30f33d0f90dc13d8cad0a7b3e70.zip |
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'mod')
133 files changed, 12285 insertions, 7334 deletions
diff --git a/mod/_well_known.php b/mod/_well_known.php index 5c5f6585f..d88bc2391 100644 --- a/mod/_well_known.php +++ b/mod/_well_known.php @@ -3,12 +3,11 @@ function _well_known_init(&$a){
if(argc() > 1) {
- switch(argv(1)) {
- case "host-meta":
- require_once('mod/hostxrd.php');
- hostxrd_init($a);
- break;
+ $arr = array('server' => $_SERVER, 'request' => $_REQUEST);
+ call_hooks('well_known', $arr);
+
+ switch(argv(1)) {
case 'zot-info':
$a->argc -= 1;
array_shift($a->argv);
@@ -17,6 +16,25 @@ function _well_known_init(&$a){ zfinger_init($a);
break;
+ case 'webfinger':
+ $a->argc -= 1;
+ array_shift($a->argv);
+ $a->argv[0] = 'wfinger';
+ require_once('mod/wfinger.php');
+ wfinger_init($a);
+ break;
+
+ case 'host-meta':
+ $a->argc -= 1;
+ array_shift($a->argv);
+ $a->argv[0] = 'hostxrd';
+ require_once('mod/hostxrd.php');
+ hostxrd_init($a);
+ break;
+
+ default:
+ break;
+
}
}
diff --git a/mod/achievements.php b/mod/achievements.php new file mode 100644 index 000000000..1910def73 --- /dev/null +++ b/mod/achievements.php @@ -0,0 +1,84 @@ +<?php + +function achievements_content(&$a) { + + if(argc() > 1) + $which = argv(1); + else { + notice( t('Requested profile is not available.') . EOL ); + return; +} + + $profile = 0; + $profile = argv(1); + profile_load($a,$which,$profile); + + $r = q("select channel_id from channel where channel_address = '%s'", + dbesc($which) + ); + if($r) { + $owner = intval($r[0]['channel_id']); + } + + $observer = $a->get_observer(); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + $perms = get_all_perms($owner,$ob_hash); + if(! $perms['view_profile']) { + notice( t('Permission denied.') . EOL); + return; + } + +// By default, all badges are false + $contactbadge = false; + $profilebadge = false; + $keywordsbadge = false; + +// Check number of contacts. Award a badge if over 10 +// We'll figure these out on each page load instead of +// writing them to the DB because that will mean one needs +// to retain their achievements - eg, you can't add +// a bunch of channels just to get your badge, and then +// delete them all again. If these become popular or +// used in profiles or something, we may need to reconsider +// and add a table for this - because this won't scale. + + $r = q("select * from abook where abook_channel = %d", + intval($owner) + ); + + if (count($r)) + $contacts = count($r); + // We're checking for 11 to adjust for the abook record for self + if ($contacts >= 11) + $contactbadge = true; + +// Check if an about field in the profile has been created. + + $r = q("select * from profile where uid = %d and about <> ''", + intval($owner) + ); + + if ($r) + $profilebadge = 1; + +// Check if keywords have been set + + $r = q("select * from profile where uid = %d and keywords <> ''", + intval($owner) + ); + + if($r) + $keywordsbadge = 1; + +// FIXME - stick ths in a template, and make it look pretty. + $o .= "Template not implemented"; + $o .= "If this is one, you get the profile badge" . $profilebadge . "<br>"; + $o .= "If this is one, you get the contact badge" . $contactbadge . "<br>"; + $o .= "If this is one you get the keywords badge" . $keywordsbadge . "<br>"; + $o .= "I haven't done the top level posts badge yet" . $toplevelpostsbadge . "<br>"; + $o .= "I haven't done the number of channels badge yet" . $channelsbadge; + + +return $o; + +} diff --git a/mod/acl.php b/mod/acl.php index 76be01ee6..fa399a9b5 100644 --- a/mod/acl.php +++ b/mod/acl.php @@ -5,6 +5,7 @@ require_once("include/acl_selectors.php"); function acl_init(&$a){ +// logger('mod_acl: ' . print_r($_REQUEST,true)); $start = (x($_REQUEST,'start')?$_REQUEST['start']:0); $count = (x($_REQUEST,'count')?$_REQUEST['count']:100); @@ -21,12 +22,11 @@ function acl_init(&$a){ } - if(! (local_user() || $type == 'x')) - return ""; + if(!(local_user())) + if($type != 'x') + killme(); - - - if ($search!=""){ + if ($search != "") { $sql_extra = " AND `name` LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " "; $sql_extra2 = "AND ( xchan_name LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " OR xchan_addr LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . ") "; @@ -39,7 +39,7 @@ function acl_init(&$a){ // count groups and contacts if ($type=='' || $type=='g'){ - $r = q("SELECT COUNT(`id`) AS g FROM `group` WHERE `deleted` = 0 AND `uid` = %d $sql_extra", + $r = q("SELECT COUNT(`id`) AS g FROM `groups` WHERE `deleted` = 0 AND `uid` = %d $sql_extra", intval(local_user()) ); $group_count = (int)$r[0]['g']; @@ -49,37 +49,52 @@ function acl_init(&$a){ if ($type=='' || $type=='c'){ $r = q("SELECT COUNT(abook_id) AS c FROM abook left join xchan on abook_xchan = xchan_hash - WHERE abook_channel = %d AND not ( abook_flags & %d ) $sql_extra2" , + WHERE abook_channel = %d AND not ( abook_flags & %d ) and not (xchan_flags & %d ) $sql_extra2" , intval(local_user()), - intval(ABOOK_FLAG_SELF|ABOOK_FLAG_BLOCKED|ABOOK_FLAG_PENDING|ABOOK_FLAG_ARCHIVE) + intval(ABOOK_FLAG_BLOCKED|ABOOK_FLAG_PENDING|ABOOK_FLAG_ARCHIVED), + intval(XCHAN_FLAGS_DELETED) ); $contact_count = (int)$r[0]['c']; + + if(intval(get_config('system','taganyone')) || intval(get_pconfig(local_user(),'system','taganyone'))) { + if(((! $r) || (! $r[0]['total'])) && $type == 'c') { + $r = q("SELECT COUNT(xchan_hash) AS c FROM xchan + WHERE not (xchan_flags & %d ) $sql_extra2" , + intval(XCHAN_FLAGS_DELETED) + ); + $contact_count = (int)$r[0]['c']; + } + } + } elseif ($type == 'm') { // autocomplete for Private Messages - $r = q("SELECT COUNT(`id`) AS c FROM `contact` - WHERE `uid` = %d AND `self` = 0 - AND `blocked` = 0 AND `pending` = 0 AND `archive` = 0 - AND `network` IN ('%s','%s','%s') $sql_extra2" , + + $r = q("SELECT count(xchan_hash) as c + FROM abook left join xchan on abook_xchan = xchan_hash + WHERE abook_channel = %d and ( (abook_their_perms = null) or (abook_their_perms & %d )) + and not ( xchan_flags & %d ) + $sql_extra2 ", intval(local_user()), - dbesc(NETWORK_DFRN), - dbesc(NETWORK_ZOT), - dbesc(NETWORK_DIASPORA) + intval(PERMS_W_MAIL), + intval(XCHAN_FLAGS_DELETED) ); - $contact_count = (int)$r[0]['c']; + + if($r) + $contact_count = (int)$r[0]['c']; } elseif ($type == 'a') { // autocomplete for Contacts - $r = q("SELECT COUNT(`id`) AS c FROM `contact` - WHERE `uid` = %d AND `self` = 0 - AND `pending` = 0 $sql_extra2" , - intval(local_user()) + $r = q("SELECT COUNT(abook_id) AS c FROM abook left join xchan on abook_xchan = xchan_hash + WHERE abook_channel = %d and not ( xchan_flags & %d ) $sql_extra2" , + intval(local_user()), + intval(XCHAN_FLAGS_DELETED) ); $contact_count = (int)$r[0]['c']; @@ -94,14 +109,14 @@ function acl_init(&$a){ if ($type=='' || $type=='g'){ - $r = q("SELECT `group`.`id`, `group`.`hash`, `group`.`name`, + $r = q("SELECT `groups`.`id`, `groups`.`hash`, `groups`.`name`, GROUP_CONCAT(DISTINCT `group_member`.`xchan` SEPARATOR ',') as uids - FROM `group`,`group_member` - WHERE `group`.`deleted` = 0 AND `group`.`uid` = %d - AND `group_member`.`gid`=`group`.`id` + FROM `groups`,`group_member` + WHERE `groups`.`deleted` = 0 AND `groups`.`uid` = %d + AND `group_member`.`gid`=`groups`.`id` $sql_extra - GROUP BY `group`.`id` - ORDER BY `group`.`name` + GROUP BY `groups`.`id` + ORDER BY `groups`.`name` LIMIT %d,%d", intval(local_user()), intval($start), @@ -121,47 +136,75 @@ function acl_init(&$a){ ); } } - + if ($type=='' || $type=='c') { - $r = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick + $r = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, abook_their_perms, abook_flags FROM abook left join xchan on abook_xchan = xchan_hash - WHERE abook_channel = %d AND not ( abook_flags & %d ) $sql_extra2 order by xchan_name asc" , + WHERE abook_channel = %d AND not ( abook_flags & %d ) and not (xchan_flags & %d ) $sql_extra2 order by xchan_name asc" , intval(local_user()), - intval(ABOOK_FLAG_SELF|ABOOK_FLAG_BLOCKED|ABOOK_FLAG_PENDING|ABOOK_FLAG_ARCHIVE) + intval(ABOOK_FLAG_BLOCKED|ABOOK_FLAG_PENDING|ABOOK_FLAG_ARCHIVED), + intval(XCHAN_FLAGS_DELETED) ); + if(intval(get_config('system','taganyone')) || intval(get_pconfig(local_user(),'system','taganyone'))) { + if((! $r) && $type == 'c') { + $r = q("SELECT substr(xchan_hash,1,18) as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags + FROM xchan + WHERE not (xchan_flags & %d ) $sql_extra2 order by xchan_name asc" , + intval(XCHAN_FLAGS_DELETED) + ); + } + } } elseif($type == 'm') { $r = q("SELECT xchan_hash as id, xchan_name as name, xchan_addr as nick, xchan_photo_s as micro, xchan_url as url FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d and ( (abook_their_perms = null) or (abook_their_perms & %d )) + and not (xchan_flags & %d) $sql_extra3 ORDER BY `xchan_name` ASC ", intval(local_user()), - intval(PERMS_W_MAIL) + intval(PERMS_W_MAIL), + intval(XCHAN_FLAGS_DELETED) ); } elseif($type == 'a') { - $r = q("SELECT abook_id as id, xchan_name as name, xchan_addr as nick, xchan_photo_s as micro, xchan_network as network, xchan_url as url, xchan_addr as attag FROM abook left join xchan on abook_xchan = xchan_hash + $r = q("SELECT abook_id as id, xchan_name as name, xchan_hash as hash, xchan_addr as nick, xchan_photo_s as micro, xchan_network as network, xchan_url as url, xchan_addr as attag , abook_their_perms FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d + and not (xchan_flags & %d) $sql_extra3 ORDER BY xchan_name ASC ", - intval(local_user()) + intval(local_user()), + intval(XCHAN_FLAGS_DELETED) + ); } elseif($type == 'x') { - $r = q("SELECT xchan_name as id, xchan_name as name, xchan_photo_s as micro, xchan_url as url from xchan - where 1 - $sql_extra3 - ORDER BY `xchan_name` ASC ", - intval(local_user()) - ); + + $r = navbar_complete($a); + $x = array(); + $x['query'] = $search; + $x['photos'] = array(); + $x['links'] = array(); + $x['suggestions'] = array(); + $x['data'] = array(); + if($r) { + foreach($r as $g) { + $x['photos'][] = $g['photo']; + $x['links'][] = $g['url']; + $x['suggestions'][] = '@' . $g['name']; + $x['data'][] = $g['name']; + } + } + echo json_encode($x); + killme(); + } else $r = array(); - if($type == 'm' || $type == 'a' || $type == 'x') { + if($type == 'm' || $type == 'a') { $x = array(); $x['query'] = $search; $x['photos'] = array(); @@ -172,7 +215,7 @@ function acl_init(&$a){ foreach($r as $g) { $x['photos'][] = $g['micro']; $x['links'][] = $g['url']; - $x['suggestions'][] = (($type === 'x') ? '@' : '') . $g['name']; + $x['suggestions'][] = $g['name']; $x['data'][] = $g['id']; } } @@ -182,14 +225,31 @@ function acl_init(&$a){ if(count($r)) { foreach($r as $g){ + if(($g['abook_their_perms'] & PERMS_W_TAGWALL) && $type == 'c') { + $contacts[] = array( + "type" => "c", + "photo" => "images/twopeople.png", + "name" => $g['name'] . '+', + "id" => $g['id'] . '+', + "xid" => $g['hash'], + "link" => $g['nick'], + "nick" => substr($g['nick'],0,strpos($g['nick'],'@')), + "self" => (($g['abook_flags'] & ABOOK_FLAG_SELF) ? 'abook-self' : ''), + "taggable" => 'taggable', + "label" => t('network') + ); + } $contacts[] = array( - "type" => "c", - "photo" => $g['micro'], - "name" => $g['name'], - "id" => $g['id'], - "xid" => $g['hash'], - "link" => $g['url'], - "nick" => $g['nick'], + "type" => "c", + "photo" => $g['micro'], + "name" => $g['name'], + "id" => $g['id'], + "xid" => $g['hash'], + "link" => $g['nick'], + "nick" => substr($g['nick'],0,strpos($g['nick'],'@')), + "self" => (($g['abook_flags'] & ABOOK_FLAG_SELF) ? 'abook-self' : ''), + "taggable" => '', + "label" => '', ); } } @@ -209,3 +269,56 @@ function acl_init(&$a){ } +function navbar_complete(&$a) { + +// logger('navbar_complete'); + + if((get_config('system','block_public')) && (! local_user()) && (! remote_user())) { + return; + } + + $dirmode = intval(get_config('system','directory_mode')); + $search = ((x($_REQUEST,'query')) ? htmlentities($_REQUEST['query'],ENT_COMPAT,'UTF-8',false) : ''); + if(! $search || mb_strlen($search) < 2) + return array(); + + $star = false; + $address = false; + + if(substr($search,0,1) === '@') + $search = substr($search,1); + + if(substr($search,0,1) === '*') { + $star = true; + $search = substr($search,1); + } + + if(strpos($search,'@') !== false) { + $address = true; + } + + if(($dirmode == DIRECTORY_MODE_PRIMARY) || ($dirmode == DIRECTORY_MODE_STANDALONE)) { + $url = z_root() . '/dirsearch'; + } + + if(! $url) { + require_once("include/dir_fns.php"); + $directory = find_upstream_directory($dirmode); + $url = $directory['url'] . '/dirsearch'; + } + + if($url) { + $query = $url . '?f=' ; + $query .= '&name=' . urlencode($search) . '&limit=50' . (($address) ? '&address=' . urlencode($search) : ''); + + $x = z_fetch_url($query); + if($x['success']) { + $t = 0; + $j = json_decode($x['body'],true); + if($j && $j['results']) { + return $j['results']; + } + } + } + return array(); +} diff --git a/mod/admin.php b/mod/admin.php index d0c904b02..464edddd4 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -1,7 +1,7 @@ <?php /** - * Friendica admin + * Red admin */ @@ -9,7 +9,7 @@ * @param App $a */ function admin_post(&$a){ - + logger('admin_post', LOGGER_DEBUG); if(!is_site_admin()) { return; @@ -24,6 +24,10 @@ function admin_post(&$a){ case 'users': admin_page_users_post($a); break; + case 'channels': + admin_page_channels_post($a); + break; + case 'plugins': if (argc() > 2 && is_file("addon/" . argv(2) . "/" . argv(2) . ".php")){ @@ -49,11 +53,15 @@ function admin_post(&$a){ if(is_ajax()) return; goaway($a->get_baseurl(true) . '/admin/themes/' . $theme ); + return; break; case 'logs': admin_page_logs_post($a); break; + case 'hubloc': + admin_page_hubloc_post($a); + break; case 'dbsync': admin_page_dbsync_post($a); break; @@ -70,6 +78,7 @@ function admin_post(&$a){ */ function admin_content(&$a) { + logger('admin_content', LOGGER_DEBUG); if(!is_site_admin()) { return login(false); } @@ -80,11 +89,13 @@ function admin_content(&$a) { // array( url, name, extra css classes ) $aside = Array( - 'site' => Array($a->get_baseurl(true)."/admin/site/", t("Site") , "site"), - 'users' => Array($a->get_baseurl(true)."/admin/users/", t("Users") , "users"), - 'plugins'=> Array($a->get_baseurl(true)."/admin/plugins/", t("Plugins") , "plugins"), - 'themes' => Array($a->get_baseurl(true)."/admin/themes/", t("Themes") , "themes"), - 'dbsync' => Array($a->get_baseurl(true)."/admin/dbsync/", t('DB updates'), "dbsync") + 'site' => Array($a->get_baseurl(true)."/admin/site/", t("Site") , "site"), + 'users' => Array($a->get_baseurl(true)."/admin/users/", t("Accounts") , "users"), + 'channels' => Array($a->get_baseurl(true)."/admin/channels/", t("Channels") , "channels"), + 'plugins' => Array($a->get_baseurl(true)."/admin/plugins/", t("Plugins") , "plugins"), + 'themes' => Array($a->get_baseurl(true)."/admin/themes/", t("Themes") , "themes"), + 'hubloc' => Array($a->get_baseurl(true)."/admin/hubloc/", t("Server") , "server"), + 'dbsync' => Array($a->get_baseurl(true)."/admin/dbsync/", t('DB updates'), "dbsync") ); /* get plugins admin page */ @@ -126,12 +137,18 @@ function admin_content(&$a) { case 'users': $o = admin_page_users($a); break; + case 'channels': + $o = admin_page_channels($a); + break; case 'plugins': $o = admin_page_plugins($a); break; case 'themes': $o = admin_page_themes($a); break; + case 'hubloc': + $o = admin_page_hubloc($a); + break; case 'logs': $o = admin_page_logs($a); break; @@ -166,18 +183,18 @@ function admin_page_summary(&$a) { // list total user accounts, expirations etc. + $r = q("SELECT COUNT(account_id) as total FROM `account`"); + $users = $r[0]['total']; + $r = q("SELECT COUNT(id) as `count` FROM `register`"); $pending = $r[0]['count']; - - $r = q("select count(*) as total from deliverq where 1"); - $deliverq = (($r) ? $r[0]['total'] : 0); - $r = q("select count(*) as total from queue where 1"); + $r = q("select count(*) as total from outq"); $queue = (($r) ? $r[0]['total'] : 0); // We can do better, but this is a quick queue status - - $queues = array( 'label' => t('Message queues'), 'deliverq' => $deliverq, 'queue' => $queue ); + + $queues = array( 'label' => t('Message queues'), 'queue' => $queue ); $t = get_markup_template("admin_summary.tpl"); @@ -188,7 +205,7 @@ function admin_page_summary(&$a) { '$users' => Array( t('Registered users'), $users), '$accounts' => $accounts, '$pending' => Array( t('Pending registrations'), $pending), - '$version' => Array( t('Version'), FRIENDICA_VERSION), + '$version' => Array( t('Version'), RED_VERSION), '$build' => get_config('system','db_version'), '$plugins' => Array( t('Active plugins'), $a->plugins ) )); @@ -207,13 +224,18 @@ function admin_page_site_post(&$a){ check_form_security_token_redirectOnErr('/admin/site', 'admin_site'); $sitename = ((x($_POST,'sitename')) ? notags(trim($_POST['sitename'])) : ''); - $banner = ((x($_POST,'banner')) ? trim($_POST['banner']) : false); + $banner = ((x($_POST,'banner')) ? trim($_POST['banner']) : false); + $admininfo = ((x($_POST,'admininfo')) ? trim($_POST['admininfo']) : false); $language = ((x($_POST,'language')) ? notags(trim($_POST['language'])) : ''); $theme = ((x($_POST,'theme')) ? notags(trim($_POST['theme'])) : ''); - $maximagesize = ((x($_POST,'maximagesize')) ? intval(trim($_POST['maximagesize'])) : 0); + $theme_mobile = ((x($_POST,'theme_mobile')) ? notags(trim($_POST['theme_mobile'])) : ''); + $theme_accessibility = ((x($_POST,'theme_accessibility')) ? notags(trim($_POST['theme_accessibility'])) : ''); + $site_channel = ((x($_POST,'site_channel')) ? notags(trim($_POST['site_channel'])) : ''); + $maximagesize = ((x($_POST,'maximagesize')) ? intval(trim($_POST['maximagesize'])) : 0); $register_policy = ((x($_POST,'register_policy')) ? intval(trim($_POST['register_policy'])) : 0); + $access_policy = ((x($_POST,'access_policy')) ? intval(trim($_POST['access_policy'])) : 0); $abandon_days = ((x($_POST,'abandon_days')) ? intval(trim($_POST['abandon_days'])) : 0); $register_text = ((x($_POST,'register_text')) ? notags(trim($_POST['register_text'])) : ''); @@ -222,12 +244,9 @@ function admin_page_site_post(&$a){ $allowed_email = ((x($_POST,'allowed_email')) ? notags(trim($_POST['allowed_email'])) : ''); $block_public = ((x($_POST,'block_public')) ? True : False); $force_publish = ((x($_POST,'publish_all')) ? True : False); + $disable_discover_tab = ((x($_POST,'disable_discover_tab')) ? True : False); + $no_login_on_homepage = ((x($_POST,'no_login_on_homepage')) ? True : False); $global_directory = ((x($_POST,'directory_submit_url')) ? notags(trim($_POST['directory_submit_url'])) : ''); - $thread_allow = ((x($_POST,'thread_allow')) ? True : False); - $no_multi_reg = ((x($_POST,'no_multi_reg')) ? True : False); - $no_openid = !((x($_POST,'no_openid')) ? True : False); - $no_regfullname = !((x($_POST,'no_regfullname')) ? True : False); - $no_utf = !((x($_POST,'no_utf')) ? True : False); $no_community_page = !((x($_POST,'no_community_page')) ? True : False); $verifyssl = ((x($_POST,'verifyssl')) ? True : False); @@ -236,11 +255,8 @@ function admin_page_site_post(&$a){ $timeout = ((x($_POST,'timeout')) ? intval(trim($_POST['timeout'])) : 60); $delivery_interval = ((x($_POST,'delivery_interval'))? intval(trim($_POST['delivery_interval'])) : 0); $poll_interval = ((x($_POST,'poll_interval'))? intval(trim($_POST['poll_interval'])) : 0); - $maxloadavg = ((x($_POST,'maxloadavg')) ? intval(trim($_POST['maxloadavg'])) : 50); - $dfrn_only = ((x($_POST,'dfrn_only')) ? True : False); - $ostatus_disabled = !((x($_POST,'ostatus_disabled')) ? True : False); - $diaspora_enabled = ((x($_POST,'diaspora_enabled')) ? True : False); - $ssl_policy = ((x($_POST,'ssl_policy')) ? intval($_POST['ssl_policy']) : 0); + $maxloadavg = ((x($_POST,'maxloadavg'))? intval(trim($_POST['maxloadavg'])) : 50); +// $ssl_policy = ((x($_POST,'ssl_policy')) ? intval($_POST['ssl_policy']) : 0); /* if($ssl_policy != intval(get_config('system','ssl_policy'))) { if($ssl_policy == SSL_POLICY_FULL) { @@ -283,11 +299,12 @@ function admin_page_site_post(&$a){ } } */ - set_config('system','ssl_policy',$ssl_policy); +// set_config('system','ssl_policy',$ssl_policy); set_config('system','delivery_interval',$delivery_interval); set_config('system','poll_interval',$poll_interval); set_config('system','maxloadavg',$maxloadavg); - set_config('config','sitename',$sitename); + set_config('system','sitename',$sitename); + set_config('system','no_login_on_homepage',$no_login_on_homepage); if ($banner=="") { del_config('system','banner'); @@ -296,17 +313,37 @@ function admin_page_site_post(&$a){ set_config('system','banner', $banner); } + if ($admininfo==''){ + del_config('system','admininfo'); + } + else { + set_config('system','admininfo', $admininfo); + } set_config('system','language', $language); set_config('system','theme', $theme); + if ( $theme_mobile === '---' ) { + del_config('system','mobile_theme'); + } else { + set_config('system','mobile_theme', $theme_mobile); + } + if ( $theme_accessibility === '---' ) { + del_config('system','accessibility_theme'); + } else { + set_config('system','accessibility_theme', $theme_accessibility); + } + + set_config('system','site_channel', $site_channel); set_config('system','maximagesize', $maximagesize); set_config('system','register_policy', $register_policy); + set_config('system','access_policy', $access_policy); set_config('system','account_abandon_days', $abandon_days); set_config('system','register_text', $register_text); set_config('system','allowed_sites', $allowed_sites); set_config('system','allowed_email', $allowed_email); set_config('system','block_public', $block_public); set_config('system','publish_all', $force_publish); + set_config('system','disable_discover_tab', $disable_discover_tab); if($global_directory=="") { del_config('system','directory_submit_url'); } @@ -314,20 +351,12 @@ function admin_page_site_post(&$a){ set_config('system','directory_submit_url', $global_directory); } - set_config('system','thread_allow', $thread_allow); - - set_config('system','block_extended_register', $no_multi_reg); - set_config('system','no_openid', $no_openid); - set_config('system','no_regfullname', $no_regfullname); set_config('system','no_community_page', $no_community_page); set_config('system','no_utf', $no_utf); set_config('system','verifyssl', $verifyssl); set_config('system','proxyuser', $proxyuser); set_config('system','proxy', $proxy); set_config('system','curl_timeout', $timeout); - set_config('system','dfrn_only', $dfrn_only); - set_config('system','ostatus_disabled', $ostatus_disabled); - set_config('system','diaspora_enabled', $diaspora_enabled); info( t('Site settings updated.') . EOL); goaway($a->get_baseurl(true) . '/admin/site' ); @@ -354,14 +383,24 @@ function admin_page_site(&$a) { $lang_choices[$t[1]] = $t[1]; } } - + /* Installed themes */ $theme_choices = array(); + $theme_choices_mobile = array(); + $theme_choices_mobile["---"] = t("No special theme for mobile devices"); + $theme_choices_accessibility = array(); + $theme_choices_accessibility["---"] =t("No special theme for accessibility"); $files = glob('view/theme/*'); if($files) { foreach($files as $file) { $f = basename($file); - $theme_name = ((file_exists($file . '/.experimental')) ? sprintf("%s - Experimental", $f) : $f); + $theme_name = ((file_exists($file . '/experimental')) ? sprintf("%s - Experimental", $f) : $f); + if (file_exists($file . '/mobile')) { + $theme_choices_mobile[$f] = $theme_name; + } + if (file_exists($file . '/accessibility')) { + $theme_choices_accessibility[$f] = $theme_name; + } $theme_choices[$f] = $theme_name; } } @@ -373,17 +412,28 @@ function admin_page_site(&$a) { $banner = 'red'; $banner = htmlspecialchars($banner); + /* Admin Info */ + $admininfo = get_config('system','admininfo'); + /* Register policy */ $register_choices = Array( - REGISTER_CLOSED => t("Closed"), - REGISTER_APPROVE => t("Requires approval"), - REGISTER_OPEN => t("Open") + REGISTER_CLOSED => t("No"), + REGISTER_APPROVE => t("Yes - with approval"), + REGISTER_OPEN => t("Yes") ); - $ssl_choices = array( - SSL_POLICY_NONE => t("No SSL policy, links will track page SSL state"), - SSL_POLICY_FULL => t("Force all links to use SSL") + /* Acess policy */ + $access_choices = Array( + ACCESS_PRIVATE => t("My site is not a public server"), + ACCESS_PAID => t("My site has paid access only"), + ACCESS_FREE => t("My site has free access only"), + ACCESS_TIERED => t("My site offers free accounts with optional paid upgrades") ); + +// $ssl_choices = array( +// SSL_POLICY_NONE => t("No SSL policy, links will track page SSL state"), +// SSL_POLICY_FULL => t("Force all links to use SSL") +// ); $t = get_markup_template("admin_site.tpl"); return replace_macros($t, array( @@ -397,22 +447,27 @@ function admin_page_site(&$a) { '$baseurl' => $a->get_baseurl(true), // name, label, value, help string, extra data... - '$sitename' => array('sitename', t("Site name"), htmlentities($a->config['sitename'], ENT_QUOTES), ""), + '$sitename' => array('sitename', t("Site name"), htmlspecialchars(get_config('system','sitename'), ENT_QUOTES, 'UTF-8'),''), '$banner' => array('banner', t("Banner/Logo"), $banner, ""), + '$admininfo' => array('admininfo', t("Administrator Information"), $admininfo, t("Contact information for site administrators. Displayed on siteinfo page. BBCode can be used here")), '$language' => array('language', t("System language"), get_config('system','language'), "", $lang_choices), '$theme' => array('theme', t("System theme"), get_config('system','theme'), t("Default system theme - may be over-ridden by user profiles - <a href='#' id='cnftheme'>change theme settings</a>"), $theme_choices), - '$ssl_policy' => array('ssl_policy', t("SSL link policy"), (string) intval(get_config('system','ssl_policy')), t("Determines whether generated links should be forced to use SSL"), $ssl_choices), - '$maximagesize' => array('maximagesize', t("Maximum image size"), get_config('system','maximagesize'), t("Maximum size in bytes of uploaded images. Default is 0, which means no limits.")), - '$register_policy' => array('register_policy', t("Register policy"), $a->config['system']['register_policy'], "", $register_choices), - '$register_text' => array('register_text', t("Register text"), htmlentities($a->config['register_text'], ENT_QUOTES, 'UTF-8'), t("Will be displayed prominently on the registration page.")), + '$theme_mobile' => array('theme_mobile', t("Mobile system theme"), get_config('system','mobile_theme'), t("Theme for mobile devices"), $theme_choices_mobile), + '$theme_accessibility' => array('theme_accessibility', t("Accessibility system theme"), get_config('system','accessibility_theme'), t("Accessibility theme"), $theme_choices_accessibility), + '$site_channel' => array('site_channel', t("Channel to use for this website's static pages"), get_config('system','site_channel'), t("Site Channel")), +// '$ssl_policy' => array('ssl_policy', t("SSL link policy"), (string) intval(get_config('system','ssl_policy')), t("Determines whether generated links should be forced to use SSL"), $ssl_choices), + '$maximagesize' => array('maximagesize', t("Maximum image size"), intval(get_config('system','maximagesize')), t("Maximum size in bytes of uploaded images. Default is 0, which means no limits.")), + '$register_policy' => array('register_policy', t("Does this site allow new member registration?"), get_config('system','register_policy'), "", $register_choices), + '$access_policy' => array('access_policy', t("Which best describes the types of account offered by this hub?"), get_config('system','access_policy'), "This is displayed on the public server site list.", $access_choices), + '$register_text' => array('register_text', t("Register text"), htmlspecialchars(get_config('system','register_text'), ENT_QUOTES, 'UTF-8'), t("Will be displayed prominently on the registration page.")), '$abandon_days' => array('abandon_days', t('Accounts abandoned after x days'), get_config('system','account_abandon_days'), t('Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit.')), '$allowed_sites' => array('allowed_sites', t("Allowed friend domains"), get_config('system','allowed_sites'), t("Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains")), '$allowed_email' => array('allowed_email', t("Allowed email domains"), get_config('system','allowed_email'), t("Comma separated list of domains which are allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains")), '$block_public' => array('block_public', t("Block public"), get_config('system','block_public'), t("Check to block public access to all otherwise public personal pages on this site unless you are currently logged in.")), '$force_publish' => array('publish_all', t("Force publish"), get_config('system','publish_all'), t("Check to force all profiles on this site to be listed in the site directory.")), - '$global_directory' => array('directory_submit_url', t("Global directory update URL"), get_config('system','directory_submit_url'), t("URL to update the global directory. If this is not set, the global directory is completely unavailable to the application.")), + '$disable_discover_tab' => array('disable_discover_tab', t("Disable discovery tab"), get_config('system','disable_discover_tab'), t("Remove the tab in the network view with public content pulled from sources chosen for this site.")), + '$no_login_on_homepage' => array('no_login_on_homepage', t("No login on Homepage"), get_config('system','no_login_on_homepage'), t("Check to hide the login form from your sites homepage when visitors arrive who are not logged in (e.g. when you put the content of the homepage in via the site channel).")), - '$no_community_page' => array('no_community_page', t("Show Community Page"), !get_config('system','no_community_page'), t("Display a Community page showing all recent public postings on this site.")), '$proxyuser' => array('proxyuser', t("Proxy user"), get_config('system','proxyuser'), ""), '$proxy' => array('proxy', t("Proxy URL"), get_config('system','proxy'), ""), '$timeout' => array('timeout', t("Network timeout"), (x(get_config('system','curl_timeout'))?get_config('system','curl_timeout'):60), t("Value is in seconds. Set to 0 for unlimited (not recommended).")), @@ -424,6 +479,74 @@ function admin_page_site(&$a) { )); } +function admin_page_hubloc_post(&$a){ + check_form_security_token_redirectOnErr('/admin/hubloc', 'admin_hubloc'); + require_once('include/zot.php'); + + //prepare for ping + + if ( $_POST['hublocid']) { + $hublocid = $_POST['hublocid']; + $arrhublocurl = q("SELECT hubloc_url FROM hubloc WHERE hubloc_id = %d ", + intval($hublocid) + ); + $hublocurl = $arrhublocurl[0]['hubloc_url'] . '/post'; + + //perform ping + $m = zot_build_packet($a->get_channel(),'ping'); + $r = zot_zot($hublocurl,$m); + //handle results and set the hubloc flags in db to make results visible + $r2 = $r['body']; + $r3 = $r2['success']; + if ( $r3['success'] == True ){ + //set HUBLOC_OFFLINE to 0 + logger(' success = true ',LOGGER_DEBUG); + } else { + //set HUBLOC_OFFLINE to 1 + logger(' success = false ', LOGGER_DEBUG); + + } + + //unfotunatly zping wont work, I guess return format is not correct + //require_once('mod/zping.php'); + //$r = zping_content($hublocurl); + //logger('zping answer: ' . $r, LOGGER_DEBUG); + + + //in case of repair store new pub key for tested hubloc (all channel with this hubloc) in db + //after repair set hubloc flags to 0 + + } + + + goaway($a->get_baseurl(true) . '/admin/hubloc' ); + return; +} + +function admin_page_hubloc(&$a) { + $o = ''; + $hubloc = q("SELECT hubloc_id, hubloc_addr, hubloc_host, hubloc_status FROM hubloc"); + + + if(! $hubloc){ + notice( t('No server found') . EOL); + goaway($a->get_baseurl(true) . '/admin/hubloc'); + } + + $t = get_markup_template("admin_hubloc.tpl"); + return replace_macros($t, array( + '$hubloc' => $hubloc, + '$th_hubloc' => array(t('ID'), t('for channel'), t('on server'), t('Status')), + '$title' => t('Administration'), + '$page' => t('Server'), + '$queues' => $queues, + //'$accounts' => $accounts, /*$accounts is empty here*/ + '$pending' => Array( t('Pending registrations'), $pending), + '$plugins' => Array( t('Active plugins'), $a->plugins ), + '$form_security_token' => get_form_security_token("admin_hubloc") + )); + return $o; +} function admin_page_dbsync(&$a) { @@ -507,19 +630,19 @@ function admin_page_users_post(&$a){ if (x($_POST,'page_users_delete')){ require_once("include/Contact.php"); foreach($users as $uid){ - user_remove($uid); + account_remove($uid,true); } notice( sprintf( tt("%s user deleted", "%s users deleted", count($users)), count($users)) ); } if (x($_POST,'page_users_approve')){ - require_once("mod/regmod.php"); + require_once('include/account.php'); foreach($pending as $hash){ user_allow($hash); } } if (x($_POST,'page_users_deny')){ - require_once("mod/regmod.php"); + require_once('include/account.php'); foreach($pending as $hash){ user_deny($hash); } @@ -549,9 +672,9 @@ function admin_page_users(&$a){ check_form_security_token_redirectOnErr('/admin/users', 'admin_users', 't'); // delete user require_once("include/Contact.php"); - user_remove($uid); + account_remove($uid,true); - notice( sprintf(t("User '%s' deleted"), $user[0]['username']) . EOL); + notice( sprintf(t("User '%s' deleted"), $account[0]['account_email']) . EOL); }; break; case "block":{ check_form_security_token_redirectOnErr('/admin/users', 'admin_users', 't'); @@ -560,7 +683,7 @@ function admin_page_users(&$a){ intval( $uid ) ); - notice( sprintf( (($account['account_flags'] & ACCOUNT_BLOCKED) ? t("User '%s' unblocked"):t("User '%s' blocked")) , $account[0]['account_email']) . EOL); + notice( sprintf( (($account[0]['account_flags'] & ACCOUNT_BLOCKED) ? t("User '%s' unblocked"):t("User '%s' blocked")) , $account[0]['account_email']) . EOL); }; break; } goaway($a->get_baseurl(true) . '/admin/users' ); @@ -569,11 +692,9 @@ function admin_page_users(&$a){ } /* get pending */ - $pending = q("SELECT `register`.*, `contact`.`name`, `user`.`email` - FROM `register` - LEFT JOIN `contact` ON `register`.`uid` = `contact`.`uid` - LEFT JOIN `user` ON `register`.`uid` = `user`.`uid`;"); - + $pending = q("SELECT account.*, register.hash from account left join register on account_id = register.uid where (account_flags & %d ) ", + intval(ACCOUNT_PENDING) + ); /* get users */ @@ -583,40 +704,43 @@ function admin_page_users(&$a){ $a->set_pager_itemspage(100); } -// FIXME this is borked since there is no more user table - - $users = q("SELECT `user` . * , `contact`.`name` , `contact`.`url` , `contact`.`micro`, `lastitem`.`lastitem_date` - FROM - (SELECT MAX(`item`.`changed`) as `lastitem_date`, `item`.`uid` - FROM `item` - WHERE `item`.`type` = 'wall' - GROUP BY `item`.`uid`) AS `lastitem` - RIGHT OUTER JOIN `user` ON `user`.`uid` = `lastitem`.`uid`, - `contact` - WHERE - `user`.`uid` = `contact`.`uid` - AND `user`.`verified` =1 - AND `contact`.`self` =1 - ORDER BY `contact`.`name` LIMIT %d, %d - ", - intval($a->pager['start']), - intval($a->pager['itemspage']) - ); + +// WEe'll still need to link email addresses to admin/users/channels or some such, but this bit doesn't exist yet. +// That's where we need to be doing last post/channel flags/etc, not here. + + + $serviceclass = (($_REQUEST['class']) ? " and account_service_class = '" . dbesc($_REQUEST['class']) . "' " : ''); + + + $order = " order by account_email asc "; + if($_REQUEST['order'] === 'expires') + $order = " order by account_expires desc "; + + $users =q("SELECT `account_id` , `account_email`, `account_lastlog`, `account_created`, `account_expires`, " . "`account_service_class`, ( account_flags & %d ) > 0 as `blocked`, " . + "(SELECT GROUP_CONCAT( ch.channel_address SEPARATOR ' ') FROM channel as ch " . + "WHERE ch.channel_account_id = ac.account_id and not (ch.channel_pageflags & %d )) as `channels` " . + "FROM account as ac where true $serviceclass $order limit %d , %d ", + intval(ACCOUNT_BLOCKED), + intval(PAGE_REMOVED), + intval($a->pager['start']), + intval($a->pager['itemspage']) + ); - function _setup_users($e){ - $accounts = Array( - t('Normal Account'), - t('Soapbox Account'), - t('Community/Celebrity Account'), - t('Automatic Friend Account') - ); - $e['page-flags'] = $accounts[$e['page-flags']]; - $e['register_date'] = relative_date($e['register_date']); - $e['login_date'] = relative_date($e['login_date']); - $e['lastitem_date'] = relative_date($e['lastitem_date']); - return $e; - } - $users = array_map("_setup_users", $users); +// function _setup_users($e){ +// $accounts = Array( +// t('Normal Account'), +// t('Soapbox Account'), +// t('Community/Celebrity Account'), +// t('Automatic Friend Account') +// ); + +// $e['page_flags'] = $accounts[$e['page-flags']]; +// $e['register_date'] = relative_date($e['register_date']); +// $e['login_date'] = relative_date($e['login_date']); +// $e['lastitem_date'] = relative_date($e['lastitem_date']); +// return $e; +// } +// $users = array_map("_setup_users", $users); $t = get_markup_template("admin_users.tpl"); @@ -627,16 +751,16 @@ function admin_page_users(&$a){ '$submit' => t('Submit'), '$select_all' => t('select all'), '$h_pending' => t('User registrations waiting for confirm'), - '$th_pending' => array( t('Request date'), t('Name'), t('Email') ), + '$th_pending' => array( t('Request date'), t('Email') ), '$no_pending' => t('No registrations.'), '$approve' => t('Approve'), '$deny' => t('Deny'), '$delete' => t('Delete'), '$block' => t('Block'), '$unblock' => t('Unblock'), - + '$h_users' => t('Users'), - '$th_users' => array( t('Name'), t('Email'), t('Register date'), t('Last login'), t('Last item'), t('Account') ), + '$th_users' => array( t('ID'), t('Email'), t('All Channels'), t('Register date'), t('Last login'), t('Expires'), t('Service Class')), '$confirm_delete_multi' => t('Selected users will be deleted!\n\nEverything these users had posted on this site will be permanently deleted!\n\nAre you sure?'), '$confirm_delete' => t('The user {0} will be deleted!\n\nEverything this user has posted on this site will be permanently deleted!\n\nAre you sure?'), @@ -655,6 +779,134 @@ function admin_page_users(&$a){ /** + * Channels admin page + * + * @param App $a + */ +function admin_page_channels_post(&$a){ + $channels = ( x($_POST, 'channel') ? $_POST['channel'] : Array() ); + + check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels'); + + if (x($_POST,'page_channels_block')){ + foreach($channels as $uid){ + q("UPDATE channel SET channel_pageflags = ( channel_pageflags ^ %d ) where channel_id = %d", + intval(PAGE_CENSORED), + intval( $uid ) + ); + proc_run('php','include/directory.php',$uid,'nopush'); + } + notice( sprintf( tt("%s channel censored/uncensored", "%s channelss censored/uncensored", count($channels)), count($channels)) ); + } + if (x($_POST,'page_channels_delete')){ + require_once("include/Contact.php"); + foreach($channels as $uid){ + channel_remove($uid,true); + } + notice( sprintf( tt("%s channel deleted", "%s channels deleted", count($channels)), count($channels)) ); + } + + goaway($a->get_baseurl(true) . '/admin/channels' ); + return; // NOTREACHED +} + +/** + * @param App $a + * @return string + */ +function admin_page_channels(&$a){ + if (argc() > 2) { + $uid = argv(3); + $channel = q("SELECT * FROM channel WHERE channel_id = %d", + intval($uid) + ); + + if (! $channel) { + notice( t('Channel not found') . EOL); + goaway($a->get_baseurl(true) . '/admin/channels' ); + } + + switch(argv(2)){ + case "delete":{ + check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels', 't'); + // delete channel + require_once("include/Contact.php"); + channel_remove($uid,true); + + notice( sprintf(t("Channel '%s' deleted"), $channel[0]['channel_name']) . EOL); + }; break; + + case "block":{ + check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels', 't'); + q("UPDATE channel SET channel_pageflags = ( channel_pageflags ^ %d ) where channel_id = %d", + intval(PAGE_CENSORED), + intval( $uid ) + ); + + notice( sprintf( (($channel[0]['channel_pageflags'] & PAGE_CENSORED) ? t("Channel '%s' uncensored"): t("Channel '%s' censored")) , $channel[0]['channel_name'] . ' (' . $channel[0]['channel_address'] . ')' ) . EOL); + }; break; + } + goaway($a->get_baseurl(true) . '/admin/channels' ); + return ''; // NOTREACHED + + } + + /* get channels */ + + $total = q("SELECT count(*) as total FROM channel where not (channel_pageflags & %d)", + intval(PAGE_REMOVED) + ); + if($total) { + $a->set_pager_total($total[0]['total']); + $a->set_pager_itemspage(100); + } + + $order = " order by channel_name asc "; + + $channels = q("SELECT * from channel where not ( channel_pageflags & %d ) $order limit %d , %d ", + intval(PAGE_REMOVED), + intval($a->pager['start']), + intval($a->pager['itemspage']) + ); + + if($channels) { + for($x = 0; $x < count($channels); $x ++) { + if($channels[$x]['channel_pageflags'] & PAGE_CENSORED) + $channels[$x]['blocked'] = true; + else + $channels[$x]['blocked'] = false; + } + } + + $t = get_markup_template("admin_channels.tpl"); + $o = replace_macros($t, array( + // strings // + '$title' => t('Administration'), + '$page' => t('Channels'), + '$submit' => t('Submit'), + '$select_all' => t('select all'), + '$delete' => t('Delete'), + '$block' => t('Censor'), + '$unblock' => t('Uncensor'), + + '$h_channels' => t('Channel'), + '$th_channels' => array( t('UID'), t('Name'), t('Address')), + + '$confirm_delete_multi' => t('Selected channels will be deleted!\n\nEverything that was posted in these channels on this site will be permanently deleted!\n\nAre you sure?'), + '$confirm_delete' => t('The channel {0} will be deleted!\n\nEverything that was posted in this channel on this site will be permanently deleted!\n\nAre you sure?'), + + '$form_security_token' => get_form_security_token("admin_channels"), + + // values // + '$baseurl' => $a->get_baseurl(true), + '$channels' => $channels, + )); + $o .= paginate($a); + return $o; +} + + +/** * Plugins admin page * * @param App $a @@ -708,12 +960,16 @@ function admin_page_plugins(&$a){ } $admin_form=""; + if (is_array($a->plugins_admin) && in_array($plugin, $a->plugins_admin)){ @require_once("addon/$plugin/$plugin.php"); - $func = $plugin.'_plugin_admin'; - $func($a, $admin_form); + if(function_exists($plugin.'_plugin_admin')) { + $func = $plugin.'_plugin_admin'; + $func($a, $admin_form); + } } - + + $t = get_markup_template("admin_plugins_details.tpl"); return replace_macros($t, array( '$title' => t('Administration'), @@ -1054,7 +1310,7 @@ readable."); // name, label, value, help string, extra data... '$debugging' => array('debugging', t("Debugging"),get_config('system','debugging'), ""), - '$logfile' => array('logfile', t("Log file"), get_config('system','logfile'), t("Must be writable by web server. Relative to your Friendica top-level directory.")), + '$logfile' => array('logfile', t("Log file"), get_config('system','logfile'), t("Must be writable by web server. Relative to your Red top-level directory.")), '$loglevel' => array('loglevel', t("Log level"), get_config('system','loglevel'), "", $log_choices), '$form_security_token' => get_form_security_token("admin_logs"), diff --git a/mod/allfriends.php b/mod/allfriends.php deleted file mode 100644 index bb4df30be..000000000 --- a/mod/allfriends.php +++ /dev/null @@ -1,60 +0,0 @@ -<?php - -require_once('include/socgraph.php'); - -function allfriends_content(&$a) { - - $o = ''; - - if(! local_user()) { - notice( t('Permission denied.') . EOL); - return; - } - - if(argc() > 1) - $cid = intval(argv(1)); - if(! $cid) - return; - - $c = q("select name, url, photo from contact where id = %d and uid = %d limit 1", - intval($cid), - intval(local_user()) - ); - - $a->page['aside'] .= '<div class="vcard">' - . '<div class="fn label">' . $c[0]['name'] . '</div>' - . '<div id="profile-photo-wrapper">' - . '<a href="/contacts/' . $cid . '"><img class="photo" width="175" height="175" - src="' . $c[0]['photo'] . '" alt="' . $c[0]['name'] . '" /></div>' - . '</div>'; - - - if(! count($c)) - return; - - $o .= '<h2>' . sprintf( t('Friends of %s'), $c[0]['name']) . '</h2>'; - - - $r = all_friends(local_user(),$cid); - - if(! count($r)) { - $o .= t('No friends to display.'); - return $o; - } - - $tpl = get_markup_template('common_friends.tpl'); - - foreach($r as $rr) { - - $o .= replace_macros($tpl,array( - '$url' => $rr['url'], - '$name' => $rr['name'], - '$photo' => $rr['photo'], - '$tags' => '' - )); - } - - $o .= cleardiv(); -// $o .= paginate($a); - return $o; -} diff --git a/mod/appman.php b/mod/appman.php new file mode 100644 index 000000000..f0a3c8a70 --- /dev/null +++ b/mod/appman.php @@ -0,0 +1,102 @@ +<?php /** @file */ + +require_once('include/apps.php'); + +function appman_post(&$a) { + + if(! local_user()) + return; + + if($_POST['url']) { + $arr = array( + 'uid' => intval($_REQUEST['uid']), + 'url' => escape_tags($_REQUEST['url']), + 'guid' => escape_tags($_REQUEST['guid']), + 'author' => escape_tags($_REQUEST['author']), + 'addr' => escape_tags($_REQUEST['addr']), + 'name' => escape_tags($_REQUEST['name']), + 'desc' => escape_tags($_REQUEST['desc']), + 'photo' => escape_tags($_REQUEST['photo']), + 'version' => escape_tags($_REQUEST['version']), + 'price' => escape_tags($_REQUEST['price']), + 'sig' => escape_tags($_REQUEST['sig']) + ); + + $_REQUEST['appid'] = app_install(local_user(),$arr); + + if(app_installed(local_user(),$arr)) + info( t('App installed.') . EOL); + + return; + } + + + $papp = app_decode($_POST['papp']); + + if(! is_array($papp)) { + notice( t('Malformed app.') . EOL); + return; + } + + if($_POST['install']) { + app_install(local_user(),$papp); + if(app_installed(local_user(),$papp)) + info( t('App installed.') . EOL); + } + + if($_POST['delete']) { + app_destroy(local_user(),$papp); + } + + if($_POST['edit']) { + return; + } + + if($_SESSION['return_url']) + goaway(z_root() . '/' . $_SESSION['return_url']); + goaway(z_root() . '/apps/personal'); + + +} + + +function appman_content(&$a) { + + if(! local_user()) { + notice( t('Permission denied.') . EOL); + return; + } + + $channel = $a->get_channel(); + $app = null; + $embed = null; + if($_REQUEST['appid']) { + $r = q("select * from app where app_id = '%s' and app_channel = %d limit 1", + dbesc($_REQUEST['appid']), + dbesc(local_user()) + ); + if($r) + $app = $r[0]; + $embed = array('embed', t('Embed code'), app_encode($app,true),'', 'onclick="this.select();"'); + + } + + return replace_macros(get_markup_template('app_create.tpl'), array( + + '$banner' => (($app) ? t('Edit App') : t('Create App')), + '$app' => $app, + '$guid' => (($app) ? $app['app_id'] : ''), + '$author' => (($app) ? $app['app_author'] : $channel['channel_hash']), + '$addr' => (($app) ? $app['app_addr'] : $channel['xchan_addr']), + '$name' => array('name', t('Name of app'),(($app) ? $app['app_name'] : ''), t('Required')), + '$url' => array('url', t('Location (URL) of app'),(($app) ? $app['app_url'] : ''), t('Required')), + '$desc' => array('desc', t('Description'),(($app) ? $app['app_desc'] : ''), ''), + '$photo' => array('photo', t('Photo icon URL'),(($app) ? $app['app_photo'] : ''), t('80 x 80 pixels - optional')), + '$version' => array('version', t('Version ID'),(($app) ? $app['app_version'] : ''), ''), + '$price' => array('price', t('Price of app'),(($app) ? $app['app_price'] : ''), ''), + '$page' => array('page', t('Location (URL) to purchase app'),(($app) ? $app['app_page'] : ''), ''), + '$embed' => $embed, + '$submit' => t('Submit') + )); + +} diff --git a/mod/apps.php b/mod/apps.php index 43540a3de..07d1968d2 100644 --- a/mod/apps.php +++ b/mod/apps.php @@ -1,16 +1,36 @@ <?php +require_once('include/apps.php'); + function apps_content(&$a) { - $apps = $a->get_apps(); + if(argc() == 2 && argv(1) == 'edit') + $mode = 'edit'; + else + $mode = 'list'; + + $apps = array(); + + $syslist = get_system_apps(); + + if(local_user()) { + $list = app_list(local_user()); + if($list) { + foreach($list as $x) { + $syslist[] = app_encode($x); + } + } + } + usort($syslist,'app_name_compare'); - if(count($apps) == 0) - notice( t('No installed applications.') . EOL); +// logger('apps: ' . print_r($syslist,true)); + foreach($syslist as $app) { + $apps[] = app_render($app,$mode); + } - $tpl = get_markup_template("apps.tpl"); - return replace_macros($tpl, array( - '$title' => t('Applications'), + return replace_macros(get_markup_template('myapps.tpl'), array( + '$title' => t('Apps'), '$apps' => $apps, )); diff --git a/mod/attach.php b/mod/attach.php index f300ec6fb..cf72d09c6 100644 --- a/mod/attach.php +++ b/mod/attach.php @@ -1,42 +1,51 @@ <?php require_once('include/security.php'); +require_once('include/attach.php'); function attach_init(&$a) { - if(argc() != 2) { + if(argc() < 2) { notice( t('Item not available.') . EOL); return; } - $hash = argv(1); + $r = attach_by_hash(argv(1),((argc() > 2) ? intval(argv(2)) : 0)); - // Check for existence, which will also provide us the owner uid - - $r = q("SELECT * FROM `attach` WHERE `hash` = '%s' LIMIT 1", - dbesc($hash) - ); - if(! count($r)) { - notice( t('Item was not found.'). EOL); + if(! $r['success']) { + notice( $r['message'] . EOL); return; } - $sql_extra = permissions_sql($r[0]['uid']); - - // Now we'll see if we can access the attachment - - $r = q("SELECT * FROM `attach` WHERE hash = '%s' $sql_extra LIMIT 1", - dbesc($hash) + $c = q("select channel_address from channel where channel_id = %d limit 1", + intval($r['data']['uid']) ); - if(! count($r)) { - notice( t('Permission denied.') . EOL); + if(! $c) return; + + + $unsafe_types = array('text/html','text/css','application/javascript'); + + if(in_array($r['data']['filetype'],$unsafe_types)) { + header('Content-type: text/plain'); + } + else { + header('Content-type: ' . $r['data']['filetype']); } - header('Content-type: ' . $r[0]['filetype']); - header('Content-disposition: attachment; filename=' . $r[0]['filename']); - echo $r[0]['data']; + header('Content-disposition: attachment; filename="' . $r['data']['filename'] . '"'); + if($r['data']['flags'] & ATTACH_FLAG_OS ) { + $istream = fopen('store/' . $c[0]['channel_address'] . '/' . $r['data']['data'],'rb'); + $ostream = fopen('php://output','wb'); + if($istream && $ostream) { + pipe_streams($istream,$ostream); + fclose($istream); + fclose($ostream); + } + } + else + echo $r['data']['data']; killme(); - // NOTREACHED -}
\ No newline at end of file + +} diff --git a/mod/auth.php b/mod/auth.php deleted file mode 100644 index 75d5fe545..000000000 --- a/mod/auth.php +++ /dev/null @@ -1,517 +0,0 @@ -<?php - - - -require_once('include/items.php'); -require_once('include/auth.php'); - - -function auth_init(&$a) { - - - $destination_url = ((x($_GET,'destination_url')) ? $_GET['destination_url'] : ''); - $challenge = ((x($_GET,'challenge')) ? $_GET['challenge'] : ''); - $sec = ((x($_GET,'sec')) ? $_GET['sec'] : ''); - - $api_version = ((x($_GET,'api_version')) ? (float) $_GET['api_version'] : 1.0); - - - if(($type === 'profile') && (! strlen($sec))) { - - $sql_extra = ''; - switch($direction) { - case (-1): - $sql_extra = sprintf(" AND ( `dfrn_id` = '%s' OR `issued_id` = '%s' ) ", dbesc($dfrn_id),dbesc($dfrn_id)); - $my_id = $dfrn_id; - break; - case 0: - $sql_extra = sprintf(" AND `issued_id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id)); - $my_id = '1:' . $dfrn_id; - break; - case 1: - $sql_extra = sprintf(" AND `dfrn_id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id)); - $my_id = '0:' . $dfrn_id; - break; - default: - goaway(z_root()); - break; // NOTREACHED - } - - $r = q("SELECT `contact`.*, `user`.`username`, `user`.`nickname` - FROM `contact` LEFT JOIN `user` ON `contact`.`uid` = `user`.`uid` - WHERE `contact`.`blocked` = 0 AND `contact`.`pending` = 0 - AND `user`.`nickname` = '%s' $sql_extra LIMIT 1", - dbesc($a->argv[1]) - ); - - if(count($r)) { - - $s = fetch_url($r[0]['poll'] . '?dfrn_id=' . $my_id . '&type=profile-check'); - - logger("dfrn_poll: old profile returns " . $s, LOGGER_DATA); - - if(strlen($s)) { - - $xml = parse_xml_string($s); - - if((int) $xml->status == 1) { - $_SESSION['authenticated'] = 1; - if(! x($_SESSION,'remote')) - $_SESSION['remote'] = array(); - - $_SESSION['remote'][] = array('cid' => $r[0]['id'],'uid' => $r[0]['uid'],'url' => $r[0]['url']); - - $_SESSION['visitor_id'] = $r[0]['id']; - $_SESSION['visitor_home'] = $r[0]['url']; - $_SESSION['visitor_handle'] = $r[0]['addr']; - $_SESSION['visitor_visiting'] = $r[0]['uid']; - info( sprintf(t('%s welcomes %s'), $r[0]['username'] , $r[0]['name']) . EOL); - // Visitors get 1 day session. - $session_id = session_id(); - $expire = time() + 86400; - q("UPDATE `session` SET `expire` = '%s' WHERE `sid` = '%s' LIMIT 1", - dbesc($expire), - dbesc($session_id) - ); - } - } - $profile = $r[0]['nickname']; - goaway((strlen($destination_url)) ? $destination_url : $a->get_baseurl() . '/channel/' . $profile); - } - goaway(z_root()); - - } - - if($type === 'profile-check' && $dfrn_version < 2.2 ) { - - if((strlen($challenge)) && (strlen($sec))) { - - q("DELETE FROM `profile_check` WHERE `expire` < " . intval(time())); - $r = q("SELECT * FROM `profile_check` WHERE `sec` = '%s' ORDER BY `expire` DESC LIMIT 1", - dbesc($sec) - ); - if(! count($r)) { - xml_status(3, 'No ticket'); - // NOTREACHED - } - $orig_id = $r[0]['dfrn_id']; - if(strpos($orig_id, ':')) - $orig_id = substr($orig_id,2); - - $c = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1", - intval($r[0]['cid']) - ); - if(! count($c)) { - xml_status(3, 'No profile'); - } - $contact = $c[0]; - - $sent_dfrn_id = hex2bin($dfrn_id); - $challenge = hex2bin($challenge); - - $final_dfrn_id = ''; - - if(($contact['duplex']) && strlen($contact['prvkey'])) { - openssl_private_decrypt($sent_dfrn_id,$final_dfrn_id,$contact['prvkey']); - openssl_private_decrypt($challenge,$decoded_challenge,$contact['prvkey']); - } - else { - openssl_public_decrypt($sent_dfrn_id,$final_dfrn_id,$contact['pubkey']); - openssl_public_decrypt($challenge,$decoded_challenge,$contact['pubkey']); - } - - $final_dfrn_id = substr($final_dfrn_id, 0, strpos($final_dfrn_id, '.')); - - if(strpos($final_dfrn_id,':') == 1) - $final_dfrn_id = substr($final_dfrn_id,2); - - if($final_dfrn_id != $orig_id) { - logger('profile_check: ' . $final_dfrn_id . ' != ' . $orig_id, LOGGER_DEBUG); - // did not decode properly - cannot trust this site - xml_status(3, 'Bad decryption'); - } - - header("Content-type: text/xml"); - echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?><dfrn_poll><status>0</status><challenge>$decoded_challenge</challenge><sec>$sec</sec></dfrn_poll>"; - killme(); - // NOTREACHED - } - else { - // old protocol - - switch($direction) { - case 1: - $dfrn_id = '0:' . $dfrn_id; - break; - case 0: - $dfrn_id = '1:' . $dfrn_id; - break; - default: - break; - } - - - q("DELETE FROM `profile_check` WHERE `expire` < " . intval(time())); - $r = q("SELECT * FROM `profile_check` WHERE `dfrn_id` = '%s' ORDER BY `expire` DESC", - dbesc($dfrn_id)); - if(count($r)) { - xml_status(1); - return; // NOTREACHED - } - xml_status(0); - return; // NOTREACHED - } - } - -} - - - -function auth_post(&$a) { - - $dfrn_id = ((x($_POST,'dfrn_id')) ? $_POST['dfrn_id'] : ''); - $challenge = ((x($_POST,'challenge')) ? $_POST['challenge'] : ''); - $url = ((x($_POST,'url')) ? $_POST['url'] : ''); - $sec = ((x($_POST,'sec')) ? $_POST['sec'] : ''); - $ptype = ((x($_POST,'type')) ? $_POST['type'] : ''); - $api_version = ((x($_POST,'api_version')) ? (float) $_POST['api_version'] : 1.0); - $perm = ((x($_POST,'perm')) ? $_POST['perm'] : 'r'); - - if($ptype === 'profile-check') { - - if((strlen($challenge)) && (strlen($sec))) { - - logger('dfrn_poll: POST: profile-check'); - - q("DELETE FROM `profile_check` WHERE `expire` < " . intval(time())); - $r = q("SELECT * FROM `profile_check` WHERE `sec` = '%s' ORDER BY `expire` DESC LIMIT 1", - dbesc($sec) - ); - if(! count($r)) { - xml_status(3, 'No ticket'); - // NOTREACHED - } - $orig_id = $r[0]['dfrn_id']; - if(strpos($orig_id, ':')) - $orig_id = substr($orig_id,2); - - $c = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1", - intval($r[0]['cid']) - ); - if(! count($c)) { - xml_status(3, 'No profile'); - } - $contact = $c[0]; - - $sent_dfrn_id = hex2bin($dfrn_id); - $challenge = hex2bin($challenge); - - $final_dfrn_id = ''; - - if(($contact['duplex']) && strlen($contact['prvkey'])) { - openssl_private_decrypt($sent_dfrn_id,$final_dfrn_id,$contact['prvkey']); - openssl_private_decrypt($challenge,$decoded_challenge,$contact['prvkey']); - } - else { - openssl_public_decrypt($sent_dfrn_id,$final_dfrn_id,$contact['pubkey']); - openssl_public_decrypt($challenge,$decoded_challenge,$contact['pubkey']); - } - - $final_dfrn_id = substr($final_dfrn_id, 0, strpos($final_dfrn_id, '.')); - - if(strpos($final_dfrn_id,':') == 1) - $final_dfrn_id = substr($final_dfrn_id,2); - - if($final_dfrn_id != $orig_id) { - logger('profile_check: ' . $final_dfrn_id . ' != ' . $orig_id, LOGGER_DEBUG); - // did not decode properly - cannot trust this site - xml_status(3, 'Bad decryption'); - } - - header("Content-type: text/xml"); - echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?><dfrn_poll><status>0</status><challenge>$decoded_challenge</challenge><sec>$sec</sec></dfrn_poll>"; - killme(); - // NOTREACHED - } - - } - - $direction = (-1); - if(strpos($dfrn_id,':') == 1) { - $direction = intval(substr($dfrn_id,0,1)); - $dfrn_id = substr($dfrn_id,2); - } - - - $r = q("SELECT * FROM `challenge` WHERE `dfrn_id` = '%s' AND `challenge` = '%s' LIMIT 1", - dbesc($dfrn_id), - dbesc($challenge) - ); - - if(! count($r)) - killme(); - - $type = $r[0]['type']; - $last_update = $r[0]['last_update']; - - $r = q("DELETE FROM `challenge` WHERE `dfrn_id` = '%s' AND `challenge` = '%s' LIMIT 1", - dbesc($dfrn_id), - dbesc($challenge) - ); - - - $sql_extra = ''; - switch($direction) { - case (-1): - $sql_extra = sprintf(" AND `issued_id` = '%s' ", dbesc($dfrn_id)); - $my_id = $dfrn_id; - break; - case 0: - $sql_extra = sprintf(" AND `issued_id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id)); - $my_id = '1:' . $dfrn_id; - break; - case 1: - $sql_extra = sprintf(" AND `dfrn_id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id)); - $my_id = '0:' . $dfrn_id; - break; - default: - goaway(z_root()); - break; // NOTREACHED - } - - - $r = q("SELECT * FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 $sql_extra LIMIT 1"); - - - if(! count($r)) - killme(); - - $contact = $r[0]; - $owner_uid = $r[0]['uid']; - $contact_id = $r[0]['id']; - - - if($type === 'reputation' && strlen($url)) { - $r = q("SELECT * FROM `contact` WHERE `url` = '%s' AND `uid` = %d LIMIT 1", - dbesc($url), - intval($owner_uid) - ); - $reputation = 0; - $text = ''; - - if(count($r)) { - $reputation = $r[0]['rating']; - $text = $r[0]['reason']; - - if($r[0]['id'] == $contact_id) { // inquiring about own reputation not allowed - $reputation = 0; - $text = ''; - } - } - - echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?> - <reputation> - <url>$url</url> - <rating>$reputation</rating> - <description>$text</description> - </reputation> - "; - killme(); - // NOTREACHED - } - else { - - // Update the writable flag if it changed - logger('dfrn_poll: post request feed: ' . print_r($_POST,true),LOGGER_DATA); - if($dfrn_version >= 2.21) { - if($perm === 'rw') - $writable = 1; - else - $writable = 0; - - if($writable != $contact['writable']) { - q("UPDATE `contact` SET `writable` = %d WHERE `id` = %d LIMIT 1", - intval($writable), - intval($contact_id) - ); - } - } - - header("Content-type: application/atom+xml"); - $o = get_feed_for($a,$dfrn_id, $a->argv[1], $last_update, $direction); - echo $o; - killme(); - - } -} - -function auth_content(&$a) { - - $dfrn_id = ((x($_GET,'dfrn_id')) ? $_GET['dfrn_id'] : ''); - $type = ((x($_GET,'type')) ? $_GET['type'] : 'data'); - $last_update = ((x($_GET,'last_update')) ? $_GET['last_update'] : ''); - $destination_url = ((x($_GET,'destination_url')) ? $_GET['destination_url'] : ''); - $sec = ((x($_GET,'sec')) ? $_GET['sec'] : ''); - $api_version = ((x($_GET,'api_version')) ? (float) $_GET['api_version'] : 1.0); - $perm = ((x($_GET,'perm')) ? $_GET['perm'] : 'r'); - - $direction = (-1); - if(strpos($dfrn_id,':') == 1) { - $direction = intval(substr($dfrn_id,0,1)); - $dfrn_id = substr($dfrn_id,2); - } - - - if($dfrn_id != '') { - // initial communication from external contact - $hash = random_string(); - - $status = 0; - - $r = q("DELETE FROM `challenge` WHERE `expire` < " . intval(time())); - - if($type !== 'profile') { - $r = q("INSERT INTO `challenge` ( `challenge`, `dfrn_id`, `expire` , `type`, `last_update` ) - VALUES( '%s', '%s', '%s', '%s', '%s' ) ", - dbesc($hash), - dbesc($dfrn_id), - intval(time() + 60 ), - dbesc($type), - dbesc($last_update) - ); - } - $sql_extra = ''; - switch($direction) { - case (-1): - if($type === 'profile') - $sql_extra = sprintf(" AND ( `dfrn_id` = '%s' OR `issued_id` = '%s' ) ", dbesc($dfrn_id),dbesc($dfrn_id)); - else - $sql_extra = sprintf(" AND `issued_id` = '%s' ", dbesc($dfrn_id)); - $my_id = $dfrn_id; - break; - case 0: - $sql_extra = sprintf(" AND `issued_id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id)); - $my_id = '1:' . $dfrn_id; - break; - case 1: - $sql_extra = sprintf(" AND `dfrn_id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id)); - $my_id = '0:' . $dfrn_id; - break; - default: - goaway(z_root()); - break; // NOTREACHED - } - - $nickname = $a->argv[1]; - - $r = q("SELECT `contact`.*, `user`.`username`, `user`.`nickname` - FROM `contact` LEFT JOIN `user` ON `contact`.`uid` = `user`.`uid` - WHERE `contact`.`blocked` = 0 AND `contact`.`pending` = 0 - AND `user`.`nickname` = '%s' $sql_extra LIMIT 1", - dbesc($nickname) - ); - - if(count($r)) { - - $challenge = ''; - $encrypted_id = ''; - $id_str = $my_id . '.' . mt_rand(1000,9999); - - if(($r[0]['duplex'] && strlen($r[0]['pubkey'])) || (! strlen($r[0]['prvkey']))) { - openssl_public_encrypt($hash,$challenge,$r[0]['pubkey']); - openssl_public_encrypt($id_str,$encrypted_id,$r[0]['pubkey']); - } - else { - openssl_private_encrypt($hash,$challenge,$r[0]['prvkey']); - openssl_private_encrypt($id_str,$encrypted_id,$r[0]['prvkey']); - } - - $challenge = bin2hex($challenge); - $encrypted_id = bin2hex($encrypted_id); - } - else { - $status = 1; - $challenge = ''; - $encrypted_id = ''; - } - - if(strlen($sec)) { - - // URL reply - - $s = post_url($r[0]['poll'], array( - 'dfrn_id' => $encrypted_id, - 'type' => 'profile-check', - 'dfrn_version' => DFRN_PROTOCOL_VERSION, - 'challenge' => $challenge, - 'sec' => $sec - )); - - $profile = ((count($r) && $r[0]['nickname']) ? $r[0]['nickname'] : $nickname); - - switch($destination_url) { - case 'profile': - $dest = $a->get_baseurl() . '/profile/' . $profile ; - break; - case 'photos': - $dest = $a->get_baseurl() . '/photos/' . $profile; - break; - case 'status': - case '': - $dest = $a->get_baseurl() . '/channel/' . $profile; - break; - default: - $dest = $destination_url; - break; - } - - logger("mod-auth: sec profile: " . $s, LOGGER_DATA); - - if(strlen($s)) { - - $j = json_decode($s); - - logger('mod-auth: profile: parsed json: ' . print_r($j,true), LOGGER_DATA); - logger('mod-auth: secure profile: challenge: ' . $j->challenge . ' expecting ' . $hash); - logger('mod-auth: secure profile: sec: ' . $j->sec . ' expecting ' . $sec); - - - if(((int) $j->status == 0) && ($j->challenge == $hash) && ($j->sec == $sec)) { - $_SESSION['authenticated'] = 1; - if(! x($_SESSION,'remote')) - $_SESSION['remote'] = array(); - $_SESSION['remote'][] = array('cid' => $r[0]['id'],'uid' => $r[0]['uid'],'url' => $r[0]['url']); - $_SESSION['visitor_id'] = $r[0]['id']; - $_SESSION['visitor_home'] = $r[0]['url']; - $_SESSION['visitor_visiting'] = $r[0]['uid']; - info( sprintf(t('%s welcomes %s'), $r[0]['username'] , $r[0]['name']) . EOL); - // Visitors get 1 day session. - $session_id = session_id(); - $expire = time() + 86400; - q("UPDATE `session` SET `expire` = '%s' WHERE `sid` = '%s' LIMIT 1", - dbesc($expire), - dbesc($session_id) - ); - } - - goaway($dest); - // NOTREACHED - - } - else { - // XML reply - header("Content-type: text/xml"); - echo '<?xml version="1.0" encoding="UTF-8"?>' . "\r\n" - . '<dfrn_poll>' . "\r\n" - . "\t" . '<status>' . $status . '</status>' . "\r\n" - . "\t" . '<dfrn_version>' . DFRN_PROTOCOL_VERSION . '</dfrn_version>' . "\r\n" - . "\t" . '<dfrn_id>' . $encrypted_id . '</dfrn_id>' . "\r\n" - . "\t" . '<challenge>' . $challenge . '</challenge>' . "\r\n" - . '</dfrn_poll>' . "\r\n" ; - killme(); - // NOTREACHED - } - } -} -} - diff --git a/mod/authtest.php b/mod/authtest.php new file mode 100644 index 000000000..b6d940db2 --- /dev/null +++ b/mod/authtest.php @@ -0,0 +1,54 @@ +<?php + +require_once('include/zot.php'); +require_once('mod/magic.php'); + +function authtest_content(&$a) { + + + $auth_success = false; + $o .= '<h3>Magic-Auth Diagnostic</h3>'; + + if(! local_user()) { + notice( t('Permission denied.') . EOL); + return $o; + } + + $o .= '<form action="authtest" method="get">'; + $o .= 'Target URL: <input type="text" style="width: 250px;" name="dest" value="' . $_GET['dest'] .'" />'; + $o .= '<input type="submit" name="submit" value="Submit" /></form>'; + + $o .= '<br /><br />'; + + if(x($_GET,'dest')) { + if(strpos($_GET['dest'],'@')) { + $_GET['dest'] = $_REQUEST['dest'] = 'https://' . substr($_GET['dest'],strpos($_GET['dest'],'@')+1) . '/channel/' . substr($_GET['dest'],0,strpos($_GET['dest'],'@')); + } + + $_REQUEST['test'] = 1; + $x = magic_init($a); + $o .= 'Local Setup returns: ' . print_r($x,true); + + + + if($x['url']) { + $z = z_fetch_url($x['url'] . '&test=1'); + if($z['success']) { + $j = json_decode($z['body'],true); + if(! $j) + $o .= 'json_decode failure from remote site. ' . print_r($z['body'],true); + $o .= 'Remote site responded: ' . print_r($j,true); + if($j['success'] && strpos($j['message'],'Authentication Success')) + $auth_success = true; + } + else { + $o .= 'fetch url failure.' . print_r($z,true); + } + } + + if(! $auth_success) + $o .= 'Authentication Failed!' . EOL; + } + + return str_replace("\n",'<br />',$o); +} diff --git a/mod/block.php b/mod/block.php new file mode 100644 index 000000000..043b0e9e8 --- /dev/null +++ b/mod/block.php @@ -0,0 +1,86 @@ +<?php + +require_once('include/items.php'); +require_once('include/conversation.php'); +require_once('include/page_widgets.php'); + +function block_init(&$a) { + + $which = argv(1); + $profile = 0; + profile_load($a,$which,$profile); + + if($a->profile['profile_uid']) + head_set_icon($a->profile['thumb']); + +} + + +function block_content(&$a) { + + if(! perm_is_allowed($a->profile['profile_uid'],get_observer_hash(),'view_pages')) { + notice( t('Permission denied.') . EOL); + return; + } + + if(argc() < 3) { + notice( t('Invalid item.') . EOL); + return; + } + + $channel_address = argv(1); + $page_id = argv(2); + + $u = q("select channel_id from channel where channel_address = '%s' limit 1", + dbesc($channel_address) + ); + + if(! $u) { + notice( t('Channel not found.') . EOL); + return; + } + + if($_REQUEST['rev']) + $revision = " and revision = " . intval($_REQUEST['rev']) . " "; + else + $revision = " order by revision desc "; + + require_once('include/security.php'); + $sql_options = item_permissions_sql($u[0]['channel_id']); + + $r = q("select item.* from item left join item_id on item.id = item_id.iid + where item.uid = %d and sid = '%s' and service = 'BUILDBLOCK' and + item_restrict = %d $sql_options $revision limit 1", + intval($u[0]['channel_id']), + dbesc($page_id), + intval(ITEM_BUILDBLOCK) + ); + + if(! $r) { + + // Check again with no permissions clause to see if it is a permissions issue + + $x = q("select item.* from item left join item_id on item.id = item_id.iid + where item.uid = %d and sid = '%s' and service = 'BUILDBLOCK' and + item_restrict = %d $revision limit 1", + intval($u[0]['channel_id']), + dbesc($page_id), + intval(ITEM_BUILDBLOCK) + ); + if($x) { + // Yes, it's there. You just aren't allowed to see it. + notice( t('Permission denied.') . EOL); + } + else { + notice( t('Page not found.') . EOL); + } + return; + } + + xchan_query($r); + $r = fetch_post_tags($r,true); + + $o .= prepare_page($r[0]); + return $o; + +} diff --git a/mod/blocks.php b/mod/blocks.php new file mode 100644 index 000000000..74a980c25 --- /dev/null +++ b/mod/blocks.php @@ -0,0 +1,103 @@ +<?php + +function blocks_content(&$a) { + + + + if(argc() > 1) + $which = argv(1); + else { + notice( t('Requested profile is not available.') . EOL ); + $a->error = 404; + return; + } + + profile_load($a,$which,0); + + + // Figure out who the page owner is. + $r = q("select channel_id from channel where channel_address = '%s'", + dbesc($which) + ); + if($r) { + $owner = intval($r[0]['channel_id']); + } + + // Block design features from visitors + + if((! local_user()) || (local_user() != $owner)) { + notice( t('Permission denied.') . EOL); + return; + } + + + + +// Get the observer, check their permissions + + $observer = $a->get_observer(); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + $perms = get_all_perms($owner,$ob_hash); + + if(! $perms['write_pages']) { + notice( t('Permission denied.') . EOL); + return; + } + +// if(local_user() && local_user() == $owner) { + // $a->set_widget('design',design_tools()); + // } + + + +// Create a status editor (for now - we'll need a WYSIWYG eventually) to create pages +// Nickname is set to the observers xchan, and profile_uid to the owners. This lets you post pages at other people's channels. +require_once ('include/conversation.php'); + $x = array( + 'webpage' => ITEM_BUILDBLOCK, + 'is_owner' => true, + 'nickname' => $a->profile['channel_address'], + 'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), + 'bang' => (($group || $cid) ? '!' : ''), + 'showacl' => false, + 'visitor' => true, + 'mimetype' => 'choose', + 'ptlabel' => t('Block Name'), + 'profile_uid' => intval($owner), + ); + + $o .= status_editor($a,$x); + + //Get a list of blocks. We can't display all them because endless scroll makes that unusable, so just list titles and an edit link. +//TODO - this should be replaced with pagelist_widget + +$r = q("select * from item_id where uid = %d and service = 'BUILDBLOCK' order by sid asc", + intval($owner) +); + + $pages = null; + + if($r) { + $pages = array(); + foreach($r as $rr) { + $pages[$rr['iid']][] = array('url' => $rr['iid'],'title' => $rr['sid']); + } + } + + +//Build the base URL for edit links + $url = z_root() . "/editblock/" . $which; +// This isn't pretty, but it works. Until I figure out what to do with the UI, it's Good Enough(TM). + return $o . replace_macros(get_markup_template("blocklist.tpl"), array( + '$baseurl' => $url, + '$edit' => t('Edit'), + '$pages' => $pages, + '$channel' => $which, + '$view' => t('View'), + '$preview' => '1', + + )); + + +} diff --git a/mod/bookmarks.php b/mod/bookmarks.php new file mode 100644 index 000000000..9ccc171fe --- /dev/null +++ b/mod/bookmarks.php @@ -0,0 +1,86 @@ +<?php + +function bookmarks_init(&$a) { + if(! local_user()) + return; + $item_id = intval($_REQUEST['item']); + if(! $item_id) + return; + + $u = $a->get_channel(); + + $i = q("select * from item where id = %d and uid = %d limit 1", + intval($item_id), + intval(local_user()) + ); + + if(! $i) + return; + + $i = fetch_post_tags($i); + + $item = $i[0]; + + $terms = get_terms_oftype($item['term'],TERM_BOOKMARK); + + if($terms && (! $item['item_restrict'])) { + require_once('include/bookmarks.php'); + + $s = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($item['author_xchan']) + ); + if(! $s) { + logger('mod_bookmarks: author lookup failed.'); + killme(); + } + foreach($terms as $t) { + bookmark_add($u,$s[0],$t,$item['item_private']); + info( t('Bookmark added') . EOL); + } + } + killme(); +} + +function bookmarks_content(&$a) { + if(! local_user()) { + notice( t('Permission denied.') . EOL); + return; + } + + + require_once('include/menu.php'); + require_once('include/conversation.php'); + + $channel = $a->get_channel(); + + $o = profile_tabs($a,true,$channel['channel_address']); + + $o .= '<h3>' . t('My Bookmarks') . '</h3>'; + + $x = menu_list(local_user(),'',MENU_BOOKMARK); + + if($x) { + foreach($x as $xx) { + $y = menu_fetch($xx['menu_name'],local_user(),get_observer_hash()); + $o .= menu_render($y,'',true); + } + } + + $o .= '<h3>' . t('My Connections Bookmarks') . '</h3>'; + + + $x = menu_list(local_user(),'',MENU_SYSTEM|MENU_BOOKMARK); + + if($x) { + foreach($x as $xx) { + $y = menu_fetch($xx['menu_name'],local_user(),get_observer_hash()); + $o .= menu_render($y,'',true); + } + } + + + + return $o; + +} + diff --git a/mod/chanman.php b/mod/chanman.php new file mode 100644 index 000000000..7a89708d7 --- /dev/null +++ b/mod/chanman.php @@ -0,0 +1,31 @@ +<?php /** @file */ + + +/** + Placeholder file at present. This is going to involve a bit of work. + + This file will deal with the deletion of channels and management of hublocs. + + We need to provide the following functionality: + + - Delete my account and all channels from the entire network + + - Delete my account and all channels from this server + + - Delete a channel from the entire network + + - Delete a channel from this server + + - List all hub locations for this channel + + - Remove this/some hub location from this channel + + - promote this/some hub location to primary + + - Remove hub location 'xyz' from this channel, (this should possibly only be allowed if that hub has been down for a period of time) + + - Some of these actions should probably require email verification + +*/ + + diff --git a/mod/channel.php b/mod/channel.php index 8dab365d8..395160d2c 100644 --- a/mod/channel.php +++ b/mod/channel.php @@ -1,22 +1,28 @@ <?php -function channel_init(&$a) { - - $a->page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . $a->get_baseurl() . '/feed/' . $which .'" />' . "\r\n" ; - -} +require_once('include/contact_widgets.php'); +require_once('include/items.php'); +require_once("include/bbcode.php"); +require_once('include/security.php'); +require_once('include/conversation.php'); +require_once('include/acl_selectors.php'); +require_once('include/permissions.php'); -function channel_aside(&$a) { - - require_once('include/contact_widgets.php'); - require_once('include/items.php'); +function channel_init(&$a) { + $which = null; if(argc() > 1) $which = argv(1); - else { - notice( t('Requested profile is not available.') . EOL ); - $a->error = 404; + if(! $which) { + if(local_user()) { + $channel = $a->get_channel(); + if($channel && $channel['channel_address']) + $which = $channel['channel_address']; + } + } + if(! $which) { + notice( t('You must be logged in to see this page.') . EOL ); return; } @@ -28,55 +34,34 @@ function channel_aside(&$a) { $profile = argv(1); } - $cat = ((x($_REQUEST,'cat')) ? htmlspecialchars($_REQUEST['cat']) : ''); + $a->page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . $a->get_baseurl() . '/feed/' . $which .'" />' . "\r\n" ; + + // Run profile_load() here to make sure the theme is set before + // we start loading content profile_load($a,$which,$profile); - $a->set_widget('archive',posted_date_widget($a->get_baseurl(true) . '/channel/' . $a->profile['nickname'],$a->profile['profile_uid'],true)); - $a->set_widget('categories',categories_widget($a->get_baseurl(true) . '/channel/' . $a->profile['nickname'],$cat)); - } - function channel_content(&$a, $update = 0, $load = false) { $category = $datequery = $datequery2 = ''; - if(argc() > 2) { - for($x = 2; $x < argc(); $x ++) { - if(is_a_date_arg(argv($x))) { - if($datequery) - $datequery2 = escape_tags(argv($x)); - else - $datequery = escape_tags(argv($x)); - } - } - } + $mid = $_GET['mid']; + $datequery = ((x($_GET,'dend') && is_a_date_arg($_GET['dend'])) ? notags($_GET['dend']) : ''); + $datequery2 = ((x($_GET,'dbegin') && is_a_date_arg($_GET['dbegin'])) ? notags($_GET['dbegin']) : ''); if(get_config('system','block_public') && (! get_account_id()) && (! remote_user())) { return login(); } - - - require_once("include/bbcode.php"); - require_once('include/security.php'); - require_once('include/conversation.php'); - require_once('include/acl_selectors.php'); - require_once('include/items.php'); - require_once('include/permissions.php'); - + $category = ((x($_REQUEST,'cat')) ? $_REQUEST['cat'] : ''); $groups = array(); - - $tab = 'posts'; $o = ''; - - $is_owner = (((local_user()) && ($a->profile['profile_uid'] == local_user())) ? true : false); - if($update) { // Ensure we've got a profile owner if updating. $a->profile['profile_uid'] = $update; @@ -87,12 +72,20 @@ function channel_content(&$a, $update = 0, $load = false) { } } + $is_owner = (((local_user()) && ($a->profile['profile_uid'] == local_user())) ? true : false); + + $channel = $a->get_channel(); $observer = $a->get_observer(); $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); $perms = get_all_perms($a->profile['profile_uid'],$ob_hash); if(! $perms['view_stream']) { + // We may want to make the target of this redirect configurable + if($perms['view_profile']) { + notice( t('Insufficient permissions. Request redirected to profile page.') . EOL); + goaway (z_root() . "/profile/" . $a->profile['channel_address']); + } notice( t('Permission denied.') . EOL); return; } @@ -100,23 +93,34 @@ function channel_content(&$a, $update = 0, $load = false) { if(! $update) { - $o .= profile_tabs($a, $is_owner, $a->profile['channel_address']); $o .= common_friends_visitor_widget($a->profile['profile_uid']); + if($channel && $is_owner) { + $channel_acl = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + } + else + $channel_acl = array(); + if($perms['post_wall']) { $x = array( 'is_owner' => $is_owner, - 'allow_location' => ((($is_owner || $observer) && $a->profile['allow_location']) ? true : false), - 'default_location' => (($is_owner) ? $a->user['default-location'] : ''), + 'allow_location' => ((($is_owner || $observer) && (intval(get_pconfig($a->profile['profile_uid'],'system','use_browser_location')))) ? true : false), + 'default_location' => (($is_owner) ? $a->profile['channel_location'] : ''), 'nickname' => $a->profile['channel_address'], 'lockstate' => (((strlen($a->profile['channel_allow_cid'])) || (strlen($a->profile['channel_allow_gid'])) || (strlen($a->profile['channel_deny_cid'])) || (strlen($a->profile['channel_deny_gid']))) ? 'lock' : 'unlock'), - 'acl' => (($is_owner) ? populate_acl($channel, false) : ''), + 'acl' => (($is_owner) ? populate_acl($channel_acl) : ''), + 'showacl' => (($is_owner) ? 'yes' : ''), 'bang' => '', - 'visitor' => (($is_owner || $observer) ? 'block' : 'none'), + 'visitor' => (($is_owner || $observer) ? true : false), 'profile_uid' => $a->profile['profile_uid'] ); @@ -135,25 +139,35 @@ function channel_content(&$a, $update = 0, $load = false) { if(($update) && (! $load)) { - $r = q("SELECT distinct(parent) AS `item_id` from item - left join abook on item.author_xchan = abook.abook_xchan - WHERE uid = %d AND item_restrict = 0 - AND (item_flags & %d) AND ( item_flags & %d ) AND ( item_flags & %d ) - AND ((abook.abook_flags & %d) = 0 or abook.abook_flags is null) - $sql_extra - ORDER BY created DESC", - intval($a->profile['profile_uid']), - intval(ITEM_WALL), - intval(ITEM_UNSEEN), - intval(ITEM_THREAD_TOP), - intval(ABOOK_FLAG_BLOCKED) - ); + if ($mid) { + $r = q("SELECT parent AS item_id from item where mid = '%s' and uid = %d AND item_restrict = 0 + AND (item_flags & %d) AND (item_flags & %d) $sql_extra limit 1", + dbesc($mid), + intval($a->profile['profile_uid']), + intval(ITEM_WALL), + intval(ITEM_UNSEEN) + ); + } else { + $r = q("SELECT distinct parent AS `item_id` from item + left join abook on item.author_xchan = abook.abook_xchan + WHERE uid = %d AND item_restrict = 0 + AND (item_flags & %d) AND ( item_flags & %d ) + AND ((abook.abook_flags & %d) = 0 or abook.abook_flags is null) + $sql_extra + ORDER BY created DESC", + intval($a->profile['profile_uid']), + intval(ITEM_WALL), + intval(ITEM_UNSEEN), + intval(ABOOK_FLAG_BLOCKED) + ); + } } else { + if(x($category)) { - $sql_extra .= protect_sprintf(file_tag_file_query('item',$category,'category')); + $sql_extra .= protect_sprintf(term_query('item', $category, TERM_CATEGORY)); } if($datequery) { @@ -163,25 +177,36 @@ function channel_content(&$a, $update = 0, $load = false) { $sql_extra2 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery2)))); } - - $a->set_pager_itemspage(40); - + $itemspage = get_pconfig(local_user(),'system','itemspage'); + $a->set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); $pager_sql = sprintf(" LIMIT %d, %d ",intval($a->pager['start']), intval($a->pager['itemspage'])); - if($load) { - $r = q("SELECT id AS item_id FROM item - left join abook on item.author_xchan = abook.abook_xchan - WHERE uid = %d AND item_restrict = 0 - AND (item_flags & %d) and (item_flags & %d) - AND ((abook.abook_flags & %d) = 0 or abook.abook_flags is null) - $sql_extra $sql_extra2 - ORDER BY created DESC $pager_sql ", - intval($a->profile['profile_uid']), - intval(ITEM_WALL), - intval(ITEM_THREAD_TOP), - intval(ABOOK_FLAG_BLOCKED) - - ); + if($load || ($_COOKIE['jsAvailable'] != 1)) { + if ($mid) { + $r = q("SELECT parent AS item_id from item where mid = '%s' and uid = %d AND item_restrict = 0 + AND (item_flags & %d) $sql_extra limit 1", + dbesc($mid), + intval($a->profile['profile_uid']), + intval(ITEM_WALL) + ); + if (! $r) { + notice( t('Permission denied.') . EOL); + } + + } else { + $r = q("SELECT distinct id AS item_id FROM item + left join abook on item.author_xchan = abook.abook_xchan + WHERE uid = %d AND item_restrict = 0 + AND (item_flags & %d) and (item_flags & %d) + AND ((abook.abook_flags & %d) = 0 or abook.abook_flags is null) + $sql_extra $sql_extra2 + ORDER BY created DESC $pager_sql ", + intval($a->profile['profile_uid']), + intval(ITEM_WALL), + intval(ITEM_THREAD_TOP), + intval(ABOOK_FLAG_BLOCKED) + ); + } } else { $r = array(); @@ -202,9 +227,15 @@ function channel_content(&$a, $update = 0, $load = false) { ); xchan_query($items); - $items = fetch_post_tags($items); + $items = fetch_post_tags($items, true); $items = conv_sort($items,'created'); + if ($load && $mid && (! count($items))) { + // This will happen if we don't have sufficient permissions + // to view the parent item (or the item itself if it is toplevel) + notice( t('Permission denied.') . EOL); + } + } else { $items = array(); } @@ -233,11 +264,14 @@ function channel_content(&$a, $update = 0, $load = false) { '$spam' => '0', '$nouveau' => '0', '$wall' => '1', + '$fh' => '0', '$page' => (($a->pager['page'] != 1) ? $a->pager['page'] : 1), '$search' => '', '$order' => '', + '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), '$file' => '', '$cats' => (($category) ? $category : ''), + '$mid' => $mid, '$dend' => $datequery, '$dbegin' => $datequery2 )); @@ -248,6 +282,7 @@ function channel_content(&$a, $update = 0, $load = false) { if($is_owner) { + $r = q("UPDATE item SET item_flags = (item_flags ^ %d) WHERE (item_flags & %d) AND (item_flags & %d) AND uid = %d ", intval(ITEM_UNSEEN), @@ -258,10 +293,17 @@ function channel_content(&$a, $update = 0, $load = false) { } - $o .= conversation($a,$items,'channel',$update,'client'); + if($_COOKIE['jsAvailable'] == 1) { + $o .= conversation($a,$items,'channel',$update,'client'); + } else { + $o .= conversation($a,$items,'channel',$update,'traditional'); + } - if(! $update) + if((! $update) || ($_COOKIE['jsAvailable'] != 1)) $o .= alt_pager($a,count($items)); + if($mid) + $o .= '<div id="content-complete"></div>'; + return $o; } diff --git a/mod/chanview.php b/mod/chanview.php index 1de4f4e1b..449a98bb1 100644 --- a/mod/chanview.php +++ b/mod/chanview.php @@ -1,9 +1,11 @@ <?php require_once('include/Contact.php'); +require_once('include/zot.php'); function chanview_content(&$a) { + $observer = $a->get_observer(); $xchan = null; $r = null; @@ -13,6 +15,11 @@ function chanview_content(&$a) { dbesc($_REQUEST['hash']) ); } + if($_REQUEST['address']) { + $r = q("select * from xchan where xchan_addr = '%s' limit 1", + dbesc($_REQUEST['address']) + ); + } elseif(local_user() && intval($_REQUEST['cid'])) { $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash @@ -22,27 +29,72 @@ function chanview_content(&$a) { ); } elseif($_REQUEST['url']) { - $r = q("select * from xchan where xchan_url = '%s' limit 1", + + // if somebody re-installed they will have more than one xchan, use the most recent name date as this is + // the most useful consistently ascending table item we have. + + $r = q("select * from xchan where xchan_url = '%s' order by xchan_name_date desc limit 1", dbesc($_REQUEST['url']) ); - if(! $r) - $r = array(array('xchan_url' => $_REQUEST['url'])); } if($r) { - $xchan = $r[0]; - if($xchan['xchan_hash']) - $a->set_widget('vcard',vcard_from_xchan($xchan)); + $a->poi = $r[0]; + } + + + // Here, let's see if we have an xchan. If we don't, how we proceed is determined by what + // info we do have. If it's a URL, we can offer to visit it directly. If it's a webbie or + // address, we can and should try to import it. If it's just a hash, we can't continue, but we + // probably wouldn't have a hash if we don't already have an xchan for this channel. + if(! $a->poi) { + logger('mod_chanview: fallback'); + // This is hackish - construct a zot address from the url + if($_REQUEST['url']) { + if(preg_match('/https?\:\/\/(.*?)(\/channel\/|\/profile\/)(.*?)$/ism',$_REQUEST['url'],$matches)) { + $_REQUEST['address'] = $matches[3] . '@' . $matches[1]; + } + logger('mod_chanview: constructed address ' . print_r($matches,true)); + } + + if($_REQUEST['address']) { + $ret = zot_finger($_REQUEST['address'],null); + if($ret['success']) { + $j = json_decode($ret['body'],true); + if($j) + import_xchan($j); + $r = q("select * from xchan where xchan_addr = '%s' limit 1", + dbesc($_REQUEST['address']) + ); + if($r) + $a->poi = $r[0]; + } + + } } - else { - notice( t('No valid channel provided.') . EOL); + + if(! $a->poi) { + notice( t('Channel not found.') . EOL); return; } - $o = replace_macros(get_markup_template('chanview.tpl'),array( - '$url' => z_root() . '/magic?f=&dest=' . $xchan['xchan_url'] . '&addr=' . $xchan['xchan_addr'] - )); - return $o; + $url = $a->poi['xchan_url']; + if($observer) + $url = zid($url); + + // let somebody over-ride the iframed viewport presentation + // or let's just declare this a failed experiment. + +// if((! local_user()) || (get_pconfig(local_user(),'system','chanview_full'))) + + goaway($url); + +// $o = replace_macros(get_markup_template('chanview.tpl'),array( +// '$url' => $url, +// '$full' => t('toggle full screen mode') +// )); + +// return $o; }
\ No newline at end of file diff --git a/mod/chat.php b/mod/chat.php new file mode 100644 index 000000000..e2428f1f7 --- /dev/null +++ b/mod/chat.php @@ -0,0 +1,235 @@ +<?php /** @file */ + +require_once('include/chat.php'); +require_once('include/bookmarks.php'); + +function chat_init(&$a) { + + $which = null; + if(argc() > 1) + $which = argv(1); + if(! $which) { + if(local_user()) { + $channel = $a->get_channel(); + if($channel && $channel['channel_address']) + $which = $channel['channel_address']; + } + } + if(! $which) { + notice( t('You must be logged in to see this page.') . EOL ); + return; + } + + $profile = 0; + $channel = $a->get_channel(); + + if((local_user()) && (argc() > 2) && (argv(2) === 'view')) { + $which = $channel['channel_address']; + $profile = argv(1); + } + + $a->page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . $a->get_baseurl() . '/feed/' . $which .'" />' . "\r\n" ; + + // Run profile_load() here to make sure the theme is set before + // we start loading content + + profile_load($a,$which,$profile); + +} + +function chat_post(&$a) { + + if($_POST['room_name']) + $room = strip_tags(trim($_POST['room_name'])); + + if((! $room) || (! local_user())) + return; + + $channel = $a->get_channel(); + + + if($_POST['action'] === 'drop') { + logger('delete chatroom'); + chatroom_destroy($channel,array('cr_name' => $room)); + goaway(z_root() . '/chat/' . $channel['channel_address']); + } + + + $arr = array('name' => $room); + $arr['allow_gid'] = perms2str($_REQUEST['group_allow']); + $arr['allow_cid'] = perms2str($_REQUEST['contact_allow']); + $arr['deny_gid'] = perms2str($_REQUEST['group_deny']); + $arr['deny_cid'] = perms2str($_REQUEST['contact_deny']); + + chatroom_create($channel,$arr); + + $x = q("select cr_id from chatroom where cr_name = '%s' and cr_uid = %d limit 1", + dbesc($room), + intval(local_user()) + ); + + if($x) + goaway(z_root() . '/chat/' . $channel['channel_address'] . '/' . $x[0]['cr_id']); + + // that failed. Try again perhaps? + + goaway(z_root() . '/chat/' . $channel['channel_address'] . '/new'); + + +} + + +function chat_content(&$a) { + + if(local_user()) + $channel = $a->get_channel(); + + $ob = $a->get_observer(); + $observer = get_observer_hash(); + if(! $observer) { + notice( t('Permission denied.') . EOL); + return; + } + + if(! perm_is_allowed($a->profile['profile_uid'],$observer,'chat')) { + notice( t('Permission denied.') . EOL); + return; + } + + if((argc() > 3) && intval(argv(2)) && (argv(3) === 'leave')) { + chatroom_leave($observer,argv(2),$_SERVER['REMOTE_ADDR']); + goaway(z_root() . '/channel/' . argv(1)); + } + + + if((argc() > 3) && intval(argv(2)) && (argv(3) === 'status')) { + $ret = array('success' => false); + $room_id = intval(argv(2)); + if(! $room_id || ! $observer) + return; + + $r = q("select * from chatroom where cr_id = %d limit 1", + intval($room_id) + ); + if(! $r) { + json_return_and_die($ret); + } + require_once('include/security.php'); + $sql_extra = permissions_sql($r[0]['cr_uid']); + + $x = q("select * from chatroom where cr_id = %d and cr_uid = %d $sql_extra limit 1", + intval($room_id), + intval($r[0]['cr_uid']) + ); + if(! $x) { + json_return_and_die($ret); + } + $y = q("select count(*) as total from chatpresence where cp_room = %d", + intval($room_id) + ); + if($y) { + $ret['success'] = true; + $ret['chatroom'] = $r[0]['cr_name']; + $ret['inroom'] = $y[0]['total']; + } + + // figure out how to present a timestamp of the last activity, since we don't know the observer's timezone. + + $z = q("select created from chat where chat_room = %d order by created desc limit 1", + intval($room_id) + ); + if($z) { + $ret['last'] = $z[0]['created']; + } + json_return_and_die($ret); + } + + + if(argc() > 2 && intval(argv(2))) { + + $room_id = intval(argv(2)); + $bookmark_link = get_bookmark_link($ob); + + $x = chatroom_enter($observer,$room_id,'online',$_SERVER['REMOTE_ADDR']); + if(! $x) + return; + $x = q("select * from chatroom where cr_id = %d and cr_uid = %d $sql_extra limit 1", + intval($room_id), + intval($a->profile['profile_uid']) + ); + if($x) { + $private = ((($x[0]['allow_cid']) || ($x[0]['allow_gid']) || ($x[0]['deny_cid']) || ($x[0]['deny_gid'])) ? true : false); + $room_name = $x[0]['cr_name']; + if($bookmark_link) + $bookmark_link .= '&url=' . z_root() . '/chat/' . argv(1) . '/' . argv(2) . '&title=' . urlencode($x[0]['cr_name']) . (($private) ? '&private=1' : '') . '&ischat=1'; + } + else { + notice( t('Room not found') . EOL); + return; + } + + $o = replace_macros(get_markup_template('chat.tpl'),array( + '$is_owner' => ((local_user() && local_user() == $x[0]['cr_uid']) ? true : false), + '$room_name' => $room_name, + '$room_id' => $room_id, + '$baseurl' => z_root(), + '$nickname' => argv(1), + '$submit' => t('Submit'), + '$leave' => t('Leave Room'), + '$drop' => t('Delete This Room'), + '$away' => t('I am away right now'), + '$online' => t('I am online'), + '$bookmark_link' => $bookmark_link, + '$bookmark' => t('Bookmark this room') + + )); + return $o; + } + + + + + + if(local_user() && argc() > 2 && argv(2) === 'new') { + + + + $channel_acl = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + + require_once('include/acl_selectors.php'); + + $o = replace_macros(get_markup_template('chatroom_new.tpl'),array( + '$header' => t('New Chatroom'), + '$name' => array('room_name',t('Chatroom Name'),'', ''), + '$permissions' => t('Permissions'), + '$acl' => populate_acl($channel_acl,false), + '$submit' => t('Submit') + )); + return $o; + } + + + + require_once('include/conversation.php'); + + $o = profile_tabs($a,((local_user() && local_user() == $a->profile['profile_uid']) ? true : false),$a->profile['channel_address']); + + require_once('include/widgets.php'); + + $o .= replace_macros(get_markup_template('chatrooms.tpl'), array( + '$header' => sprintf( t('%1$s\'s Chatrooms'), $a->profile['name']), + '$baseurl' => z_root(), + '$nickname' => $channel['channel_address'], + '$rooms' => widget_chatroom_list(array()), + '$newroom' => t('New Chatroom'), + '$is_owner' => ((local_user() && local_user() == $a->profile['profile_uid']) ? 1 : 0) + )); + + return $o; + +} diff --git a/mod/chatsvc.php b/mod/chatsvc.php new file mode 100644 index 000000000..43aa3d3c0 --- /dev/null +++ b/mod/chatsvc.php @@ -0,0 +1,159 @@ +<?php /** @file */ + +require_once('include/security.php'); + +function chatsvc_init(&$a) { + +//logger('chatsvc'); + + $ret = array('success' => false); + + $a->data['chat']['room_id'] = intval($_REQUEST['room_id']); + $x = q("select cr_uid from chatroom where cr_id = %d and cr_id != 0 limit 1", + intval($a->data['chat']['room_id']) + ); + if(! $x) + json_return_and_die($ret); + + $a->data['chat']['uid'] = $x[0]['cr_uid']; + + if(! perm_is_allowed($a->data['chat']['uid'],get_observer_hash(),'chat')) { + json_return_and_die($ret); + } + +} + +function chatsvc_post(&$a) { + + $ret = array('success' => false); + + $room_id = $a->data['chat']['room_id']; + $text = escape_tags($_REQUEST['chat_text']); + if(! $text) + return; + + $sql_extra = permissions_sql($a->data['chat']['uid']); + + $r = q("select * from chatroom where cr_uid = %d and cr_id = %d $sql_extra", + intval($a->data['chat']['uid']), + intval($a->data['chat']['room_id']) + ); + if(! $r) + json_return_and_die($ret); + + $arr = array( + 'chat_room' => $a->data['chat']['room_id'], + 'chat_xchan' => get_observer_hash(), + 'chat_text' => $text + ); + + call_hooks('chat_post',$arr); + + $x = q("insert into chat ( chat_room, chat_xchan, created, chat_text ) + values( %d, '%s', '%s', '%s' )", + intval($a->data['chat']['room_id']), + dbesc(get_observer_hash()), + dbesc(datetime_convert()), + dbesc($arr['chat_text']) + ); + + $ret['success'] = true; + json_return_and_die($ret); +} + +function chatsvc_content(&$a) { + + $status = strip_tags($_REQUEST['status']); + $room_id = intval($a->data['chat']['room_id']); + $stopped = ((x($_REQUEST,'stopped') && intval($_REQUEST['stopped'])) ? true : false); + + if($status && $room_id) { + + $x = q("select channel_address from channel where channel_id = %d limit 1", + intval($a->data['chat']['uid']) + ); + + $r = q("update chatpresence set cp_status = '%s', cp_last = '%s' where cp_room = %d and cp_xchan = '%s' and cp_client = '%s' limit 1", + dbesc($status), + dbesc(datetime_convert()), + intval($room_id), + dbesc(get_observer_hash()), + dbesc($_SERVER['REMOTE_ADDR']) + ); + + goaway(z_root() . '/chat/' . $x[0]['channel_address'] . '/' . $room_id); + } + + if(! $stopped) { + + $lastseen = intval($_REQUEST['last']); + + $ret = array('success' => false); + + $sql_extra = permissions_sql($a->data['chat']['uid']); + + $r = q("select * from chatroom where cr_uid = %d and cr_id = %d $sql_extra", + intval($a->data['chat']['uid']), + intval($a->data['chat']['room_id']) + ); + if(! $r) + json_return_and_die($ret); + + $inroom = array(); + + $r = q("select * from chatpresence left join xchan on xchan_hash = cp_xchan where cp_room = %d order by xchan_name", + intval($a->data['chat']['room_id']) + ); + if($r) { + foreach($r as $rr) { + switch($rr['cp_status']) { + case 'away': + $status = t('Away'); + break; + case 'online': + default: + $status = t('Online'); + break; + } + + $inroom[] = array('img' => zid($rr['xchan_photo_m']), 'img_type' => $rr['xchan_photo_mimetype'],'name' => $rr['xchan_name'], status => $status); + } + } + + $chats = array(); + + $r = q("select * from chat left join xchan on chat_xchan = xchan_hash where chat_room = %d and chat_id > %d order by created", + intval($a->data['chat']['room_id']), + intval($lastseen) + ); + if($r) { + foreach($r as $rr) { + $chats[] = array( + 'id' => $rr['chat_id'], + 'img' => zid($rr['xchan_photo_m']), + 'img_type' => $rr['xchan_photo_mimetype'], + 'name' => $rr['xchan_name'], + 'isotime' => datetime_convert('UTC', date_default_timezone_get(), $rr['created'], 'c'), + 'localtime' => datetime_convert('UTC', date_default_timezone_get(), $rr['created'], 'r'), + 'text' => smilies(bbcode($rr['chat_text'])) + ); + } + } + } + + $r = q("update chatpresence set cp_last = '%s' where cp_room = %d and cp_xchan = '%s' and cp_client = '%s' limit 1", + dbesc(datetime_convert()), + intval($a->data['chat']['room_id']), + dbesc(get_observer_hash()), + dbesc($_SERVER['REMOTE_ADDR']) + ); + + $ret['success'] = true; + if(! $stopped) { + $ret['inroom'] = $inroom; + $ret['chats'] = $chats; + } + json_return_and_die($ret); + +} + diff --git a/mod/cloud.php b/mod/cloud.php new file mode 100644 index 000000000..3606325bd --- /dev/null +++ b/mod/cloud.php @@ -0,0 +1,134 @@ +<?php + + use Sabre\DAV; + + require_once('vendor/autoload.php'); + + + // workaround for HTTP-auth in CGI mode + if(x($_SERVER,'REDIRECT_REMOTE_USER')) { + $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"],6)) ; + if(strlen($userpass)) { + list($name, $password) = explode(':', $userpass); + $_SERVER['PHP_AUTH_USER'] = $name; + $_SERVER['PHP_AUTH_PW'] = $password; + } + } + + if(x($_SERVER,'HTTP_AUTHORIZATION')) { + $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"],6)) ; + if(strlen($userpass)) { + list($name, $password) = explode(':', $userpass); + $_SERVER['PHP_AUTH_USER'] = $name; + $_SERVER['PHP_AUTH_PW'] = $password; + } + } + + + + + +function cloud_init(&$a) { + + require_once('include/reddav.php'); + + if(! is_dir('store')) + mkdir('store',STORAGE_DEFAULT_PERMISSIONS,false); + + $which = null; + if(argc() > 1) + $which = argv(1); + + $profile = 0; + $channel = $a->get_channel(); + + $a->page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . $a->get_baseurl() . '/feed/' . $which .'" />' . "\r\n" ; + + if($which) + profile_load($a,$which,$profile); + + + + + $auth = new RedBasicAuth(); + + $ob_hash = get_observer_hash(); + + if($ob_hash) { + if(local_user()) { + $channel = $a->get_channel(); + $auth->setCurrentUser($channel['channel_address']); + $auth->channel_name = $channel['channel_address']; + $auth->channel_id = $channel['channel_id']; + $auth->channel_hash = $channel['channel_hash']; + if($channel['channel_timezone']) + $auth->timezone = $channel['channel_timezone']; + } + $auth->observer = $ob_hash; + } + + if($_GET['davguest']) + $_SESSION['davguest'] = true; + + + + $_SERVER['QUERY_STRING'] = str_replace(array('?f=','&f='),array('',''),$_SERVER['QUERY_STRING']); + $_SERVER['QUERY_STRING'] = strip_zids($_SERVER['QUERY_STRING']); + $_SERVER['QUERY_STRING'] = preg_replace('/[\?&]davguest=(.*?)([\?&]|$)/ism','',$_SERVER['QUERY_STRING']); + + $_SERVER['REQUEST_URI'] = str_replace(array('?f=','&f='),array('',''),$_SERVER['REQUEST_URI']); + $_SERVER['REQUEST_URI'] = strip_zids($_SERVER['REQUEST_URI']); + $_SERVER['REQUEST_URI'] = preg_replace('/[\?&]davguest=(.*?)([\?&]|$)/ism','',$_SERVER['REQUEST_URI']); + + $rootDirectory = new RedDirectory('/',$auth); + $server = new DAV\Server($rootDirectory); + $lockBackend = new DAV\Locks\Backend\File('store/[data]/locks'); + $lockPlugin = new DAV\Locks\Plugin($lockBackend); + + $server->addPlugin($lockPlugin); + + // The next section of code allows us to bypass prompting for http-auth if a FILE is being accessed anonymously and permissions + // allow this. This way one can create hotlinks to public media files in their cloud and anonymous viewers won't get asked to login. + // If a DIRECTORY is accessed or there are permission issues accessing the file and we aren't previously authenticated via zot, + // prompt for HTTP-auth. This will be the default case for mounting a DAV directory. + // In order to avoid prompting for passwords for viewing a DIRECTORY, add the URL query parameter 'davguest=1' + + $isapublic_file = false; + $davguest = ((x($_SESSION,'davguest')) ? true : false); + + if((! $auth->observer) && ($_SERVER['REQUEST_METHOD'] === 'GET')) { + try { + $x = RedFileData('/' . $a->cmd,$auth); + if($x instanceof RedFile) + $isapublic_file = true; + } + catch ( Exception $e ) { + $isapublic_file = false; + } + } + + if((! $auth->observer) && (! $isapublic_file) && (! $davguest)) { + try { + $auth->Authenticate($server, t('Red Matrix - Guests: Username: {your email address}, Password: +++')); + } + catch ( Exception $e) { + logger('mod_cloud: auth exception' . $e->getMessage()); + http_status_exit($e->getHTTPCode(),$e->getMessage()); + } + } + +// $browser = new DAV\Browser\Plugin(); + + $browser = new RedBrowser($auth); + + $auth->setBrowserPlugin($browser); + + + $server->addPlugin($browser); + + + // All we need to do now, is to fire up the server + $server->exec(); + + killme(); +}
\ No newline at end of file diff --git a/mod/common.php b/mod/common.php index 617b5b670..e19a9d3a9 100644 --- a/mod/common.php +++ b/mod/common.php @@ -2,107 +2,66 @@ require_once('include/socgraph.php'); -function common_content(&$a) { +function common_init(&$a) { - $o = ''; + if(argc() > 1 && intval(argv(1))) + $channel_id = intval(argv(1)); + else { + notice( t('No channel.') . EOL ); + $a->error = 404; + return; + } - $cmd = $a->argv[1]; - $uid = intval($a->argv[2]); - $cid = intval($a->argv[3]); - $zcid = 0; + $x = q("select channel_address from channel where channel_id = %d limit 1", + intval($channel_id) + ); - if($cmd !== 'loc' && $cmd != 'rem') - return; - if(! $uid) - return; + if($x) + profile_load($a,$x[0]['channel_address'],0); - if($cmd === 'loc' && $cid) { - $c = q("select name, url, photo from contact where id = %d and uid = %d limit 1", - intval($cid), - intval($uid) - ); - } - else { - $c = q("select name, url, photo from contact where self = 1 and uid = %d limit 1", - intval($uid) - ); - } - - $a->page['aside'] .= '<div class="vcard">' - . '<div class="fn label">' . $c[0]['name'] . '</div>' - . '<div id="profile-photo-wrapper">' - . '<img class="photo" width="175" height="175" - src="' . $c[0]['photo'] . '" alt="' . $c[0]['name'] . '" /></div>' - . '</div>'; - - - if(! count($c)) - return; +} - $o .= '<h2>' . t('Common Friends') . '</h2>'; - - - if(! $cid) { - if(get_my_url()) { - $r = q("select id from contact where nurl = '%s' and uid = %d limit 1", - dbesc(normalise_link(get_my_url())), - intval($profile_uid) - ); - if(count($r)) - $cid = $r[0]['id']; - else { - $r = q("select id from gcontact where nurl = '%s' limit 1", - dbesc(normalise_link(get_my_url())) - ); - if(count($r)) - $zcid = $r[0]['id']; - } - } - } +function common_content(&$a) { + $o = ''; + if(! $a->profile['profile_uid']) + return; - if($cid == 0 && $zcid == 0) - return; + $observer_hash = get_observer_hash(); - if($cid) - $t = count_common_friends($uid,$cid); - else - $t = count_common_friends_zcid($uid,$zcid); + if(! perm_is_allowed($a->profile['profile_uid'],$observer_hash,'view_contacts')) { + notice( t('Permission denied.') . EOL); + return; + } + $o .= '<h2>' . t('Common connections') . '</h2>'; - $a->set_pager_total($t); + $t = count_common_friends($a->profile['profile_uid'],$observer_hash); if(! $t) { - notice( t('No contacts in common.') . EOL); + notice( t('No connections in common.') . EOL); return $o; } + $r = common_friends($a->profile['profile_uid'],$observer_hash); - if($cid) - $r = common_friends($uid,$cid); - else - $r = common_friends_zcid($uid,$zcid); + if($r) { + $tpl = get_markup_template('common_friends.tpl'); - if(! count($r)) { - return $o; - } - - $tpl = get_markup_template('common_friends.tpl'); + foreach($r as $rr) { + $o .= replace_macros($tpl,array( + '$url' => $rr['xchan_url'], + '$name' => $rr['xchan_name'], + '$photo' => $rr['xchan_photo_m'], + '$tags' => '' + )); + } - foreach($r as $rr) { - - $o .= replace_macros($tpl,array( - '$url' => $rr['url'], - '$name' => $rr['name'], - '$photo' => $rr['photo'], - '$tags' => '' - )); + $o .= cleardiv(); } - $o .= cleardiv(); -// $o .= paginate($a); return $o; } diff --git a/mod/community.php b/mod/community.php deleted file mode 100644 index 4f6c3d3c9..000000000 --- a/mod/community.php +++ /dev/null @@ -1,105 +0,0 @@ -<?php - -function community_init(&$a) { - if(! local_user()) { - unset($_SESSION['theme']); - unset($_SESSION['mobile-theme']); - } - - -} - - -function community_content(&$a, $update = 0) { - - $o = ''; - - if((get_config('system','block_public')) && (! local_user()) && (! remote_user())) { - notice( t('Public access denied.') . EOL); - return; - } - - if(get_config('system','no_community_page')) { - notice( t('Not available.') . EOL); - return; - } - - require_once("include/bbcode.php"); - require_once('include/security.php'); - require_once('include/conversation.php'); - - - $o .= '<h3>' . t('Community') . '</h3>'; - if(! $update) { - nav_set_selected('community'); - $o .= '<div id="live-community"></div>' . "\r\n"; - $o .= "<script> var profile_uid = -1; var netargs = '/?f='; var profile_page = " . $a->pager['page'] . "; </script>\r\n"; - } - - if(x($a->data,'search')) - $search = notags(trim($a->data['search'])); - else - $search = ((x($_GET,'search')) ? notags(trim(rawurldecode($_GET['search']))) : ''); - - - // Here is the way permissions work in this module... - // Only public posts can be shown - // OR your own posts if you are a logged in member - - if(! get_pconfig(local_user(),'system','alt_pager')) { - $r = q("SELECT COUNT(distinct(`item`.`uri`)) AS `total` - FROM `item` LEFT JOIN `contact` ON `contact`.`id` = `item`.`contact-id` LEFT JOIN `user` ON `user`.`uid` = `item`.`uid` - WHERE `item`.`visible` = 1 AND `item`.`deleted` = 0 and `item`.`moderated` = 0 - AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' - AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = '' - AND `item`.`private` = 0 AND `item`.`wall` = 1 AND `user`.`hidewall` = 0 - AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0" - ); - - if(count($r)) - $a->set_pager_total($r[0]['total']); - - if(! $r[0]['total']) { - info( t('No results.') . EOL); - return $o; - } - - } - - $r = q("SELECT distinct(`item`.`uri`), `item`.*, `item`.`id` AS `item_id`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`alias`, `contact`.`rel`, - `contact`.`network`, `contact`.`thumb`, `contact`.`self`, `contact`.`writable`, - `contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid`, - `user`.`nickname`, `user`.`hidewall` - FROM `item` LEFT JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - LEFT JOIN `user` ON `user`.`uid` = `item`.`uid` - WHERE `item`.`visible` = 1 AND `item`.`deleted` = 0 and `item`.`moderated` = 0 - AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' - AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = '' - AND `item`.`private` = 0 AND `item`.`wall` = 1 AND `user`.`hidewall` = 0 - AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0 group by `item`.`uri` - ORDER BY `received` DESC LIMIT %d, %d ", - intval($a->pager['start']), - intval($a->pager['itemspage']) - - ); - - if(! count($r)) { - info( t('No results.') . EOL); - return $o; - } - - // we behave the same in message lists as the search module - - $o .= conversation($a,$r,'community',$update); - - if(! get_pconfig(local_user(),'system','alt_pager')) { - $o .= paginate($a); - } - else { - $o .= alt_pager($a,count($r)); - } - - return $o; -} - diff --git a/mod/connect.php b/mod/connect.php new file mode 100644 index 000000000..f7748bcaf --- /dev/null +++ b/mod/connect.php @@ -0,0 +1,124 @@ +<?php /** @file */ + + +require_once('include/Contact.php'); +require_once('include/contact_widgets.php'); +require_once('include/items.php'); + + +function connect_init(&$a) { + if(argc() > 1) + $which = argv(1); + else { + notice( t('Requested profile is not available.') . EOL ); + $a->error = 404; + return; + } + + $r = q("select * from channel where channel_address = '%s' limit 1", + dbesc($which) + ); + + if($r) + $a->data['channel'] = $r[0]; + + profile_load($a,$which,''); +} + +function connect_post(&$a) { + + if(! array_key_exists('channel', $a->data)) + return; + + $edit = ((local_user() && (local_user() == $a->data['channel']['channel_id'])) ? true : false); + + if($edit) { + $has_premium = (($a->data['channel']['channel_pageflags'] & PAGE_PREMIUM) ? 1 : 0); + $premium = (($_POST['premium']) ? intval($_POST['premium']) : 0); + $text = escape_tags($_POST['text']); + + if($has_premium != $premium) { + $r = q("update channel set channel_pageflags = ( channel_pageflags ^ %d ) where channel_id = %d limit 1", + intval(PAGE_PREMIUM), + intval(local_user()) + ); + proc_run('php','include/notifier.php','refresh_all',$a->data['channel']['channel_id']); + } + set_pconfig($a->data['channel']['channel_id'],'system','selltext',$text); + // reload the page completely to get fresh data + goaway(z_root() . '/' . $a->query_string); + + } + + $url = ''; + $observer = $a->get_observer(); + if(($observer) && ($_POST['submit'] === t('Continue'))) { + if($observer['xchan_follow']) + $url = sprintf($observer['xchan_follow'],urlencode($a->data['channel']['channel_address'] . '@' . $a->get_hostname())); + if(! $url) { + $r = q("select * from hubloc where hubloc_hash = '%s' order by hubloc_id desc limit 1", + dbesc($observer['xchan_hash']) + ); + if($r) + $url = $r[0]['hubloc_url'] . '/follow?f=&url=' . urlencode($a->data['channel']['channel_address'] . '@' . $a->get_hostname()); + } + } + if($url) + goaway($url . '&confirm=1'); + else + notice('Unable to connect to your home hub location.'); + +} + + + +function connect_content(&$a) { + + $edit = ((local_user() && (local_user() == $a->data['channel']['channel_id'])) ? true : false); + + $text = get_pconfig($a->data['channel']['channel_id'],'system','selltext'); + + if($edit) { + + $o = replace_macros(get_markup_template('sellpage_edit.tpl'),array( + '$header' => t('Premium Channel Setup'), + '$address' => $a->data['channel']['channel_address'], + '$premium' => array('premium', t('Enable premium channel connection restrictions'),(($a->data['channel']['channel_pageflags'] & PAGE_PREMIUM) ? '1' : ''),''), + '$lbl_about' => t('Please enter your restrictions or conditions, such as paypal receipt, usage guidelines, etc.'), + '$text' => $text, + '$desc' => t('This channel may require additional steps or acknowledgement of the following conditions prior to connecting:'), + '$lbl2' => t('Potential connections will then see the following text before proceeding:'), + '$desc2' => t('By continuing, I certify that I have complied with any instructions provided on this page.'), + '$submit' => t('Submit'), + + + )); + return $o; + } + else { + if(! $text) + $text = t('(No specific instructions have been provided by the channel owner.)'); + + $submit = replace_macros(get_markup_template('sellpage_submit.tpl'), array( + '$continue' => t('Continue'), + '$address' => $a->data['channel']['channel_address'] + )); + + $o = replace_macros(get_markup_template('sellpage_view.tpl'),array( + '$header' => t('Restricted or Premium Channel'), + '$desc' => t('This channel may require additional steps or acknowledgement of the following conditions prior to connecting:'), + '$text' => prepare_text($text), + + '$desc2' => t('By continuing, I certify that I have complied with any instructions provided on this page.'), + '$submit' => $submit, + + )); + + $arr = array('channel' => $a->data['channel'],'observer' => $a->get_observer(), 'sellpage' => $o, 'submit' => $submit); + call_hooks('connect_premium', $arr); + $o = $arr['sellpage']; + + } + + return $o; +}
\ No newline at end of file diff --git a/mod/connections.php b/mod/connections.php index a12f51e68..b9df3c2b7 100644 --- a/mod/connections.php +++ b/mod/connections.php @@ -6,41 +6,19 @@ require_once('include/contact_selectors.php'); require_once('include/group.php'); require_once('include/contact_widgets.php'); require_once('include/zot.php'); +require_once('include/widgets.php'); function connections_init(&$a) { if(! local_user()) return; - if((argc() == 2) && intval(argv(1))) { - $r = q("SELECT abook.*, xchan.* - FROM abook left join xchan on abook_xchan = xchan_hash - WHERE abook_channel = %d and abook_id = %d LIMIT 1", - intval(local_user()), - intval(argv(1)) - ); - if($r) { - $a->data['abook'] = $r[0]; - } - } -} - -function connections_aside(&$a) { - - if(x($a->data,'abook')) { - $a->set_widget('vcard',vcard_from_xchan($a->data['abook'])); - } - else { - $a->set_widget('follow', follow_widget()); - } - - $a->set_widget('collections', group_side('connnections','group',false,0,((array_key_exists('abook',$a->data)) ? $a->data['abook']['abook_id'] : ''))); - $a->set_widget('findpeople',findpeople_widget()); + $channel = $a->get_channel(); + if($channel) + head_set_icon($channel['xchan_photo_s']); } - - function connections_post(&$a) { if(! local_user()) @@ -57,16 +35,16 @@ function connections_post(&$a) { if(! $orig_record) { notice( t('Could not access contact record.') . EOL); - goaway($a->get_baseurl(true) . '/connnections'); + goaway(z_root() . '/connections'); return; // NOTREACHED } call_hooks('contact_edit_post', $_POST); - $profile_id = intval($_POST['profile-assign']); + $profile_id = $_POST['profile_assign']; if($profile_id) { - $r = q("SELECT `id` FROM `profile` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($profile_id), + $r = q("SELECT profile_guid FROM profile WHERE profile_guid = '%s' AND `uid` = %d LIMIT 1", + dbesc($profile_id), intval(local_user()) ); if(! count($r)) { @@ -93,25 +71,57 @@ function connections_post(&$a) { } } - $r = q("UPDATE abook SET abook_profile = %d, abook_my_perms = %d , abook_closeness = %d + $abook_flags = $orig_record[0]['abook_flags']; + $new_friend = false; + + + if(($_REQUEST['pending']) && ($abook_flags & ABOOK_FLAG_PENDING)) { + $abook_flags = ( $abook_flags ^ ABOOK_FLAG_PENDING ); + $new_friend = true; + } + + $r = q("UPDATE abook SET abook_profile = '%s', abook_my_perms = %d , abook_closeness = %d, abook_flags = %d where abook_id = %d AND abook_channel = %d LIMIT 1", - intval($profile_id), + dbesc($profile_id), intval($abook_my_perms), intval($closeness), + intval($abook_flags), intval($contact_id), intval(local_user()) ); + if($r) info( t('Connection updated.') . EOL); else - notice( t('Failed to update connnection record.') . EOL); + notice( t('Failed to update connection record.') . EOL); - - if((x($a->data,'abook')) && $a->data['abook']['abook_my_perms'] != $abook_my_perms) { - // FIXME - this message type is not yet handled in the notifier + if((x($a->data,'abook')) && $a->data['abook']['abook_my_perms'] != $abook_my_perms + && (! ($a->data['abook']['abook_flags'] & ABOOK_FLAG_SELF))) { proc_run('php', 'include/notifier.php', 'permission_update', $contact_id); } + if($new_friend) { + $channel = $a->get_channel(); + $default_group = $channel['channel_default_group']; + if($default_group) { + require_once('include/group.php'); + $g = group_rec_byhash(local_user(),$default_group); + if($g) + group_add_member(local_user(),'',$a->data['abook_xchan'],$g['id']); + } + + + + // Check if settings permit ("post new friend activity" is allowed, and + // friends in general or this friend in particular aren't hidden) + // and send out a new friend activity + // TODO + + // pull in a bit of content if there is any to pull in + proc_run('php','include/onepoll.php',$contact_id); + + } + // Refresh the structure in memory with the new data $r = q("SELECT abook.*, xchan.* @@ -120,311 +130,119 @@ function connections_post(&$a) { intval(local_user()), intval($contact_id) ); - if($r) + if($r) { $a->data['abook'] = $r[0]; - - return; - -} - - - -function connections_content(&$a) { - - $sort_type = 0; - $o = ''; - nav_set_selected('connections'); - - - if(! local_user()) { - notice( t('Permission denied.') . EOL); - return; } - if(argc() == 3) { - - $contact_id = intval(argv(1)); - if(! $contact_id) - return; - - $cmd = argv(2); - - $orig_record = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash - WHERE abook_id = %d AND abook_channel = %d AND NOT ( abook_flags & %d ) and not ( abook_flags & %d ) LIMIT 1", - intval($contact_id), - intval(local_user()), - intval(ABOOK_FLAG_SELF), - intval(ABOOK_FLAG_PENDING) - ); - - if(! count($orig_record)) { - notice( t('Could not access address book record.') . EOL); - goaway($a->get_baseurl(true) . '/connections'); - } - - if($cmd === 'update') { - - // pull feed and consume it, which should subscribe to the hub. - proc_run('php',"include/poller.php","$contact_id"); - goaway($a->get_baseurl(true) . '/connections/' . $contact_id); - - } - - if($cmd === 'refresh') { - if(! zot_refresh($orig_record[0],get_app()->get_channel())) - notice( t('Refresh failed - channel is currently unavailable.') ); - goaway($a->get_baseurl(true) . '/connections/' . $contact_id); - } - - if($cmd === 'block') { - if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_BLOCKED)) - info((($orig_record[0]['abook_flags'] & ABOOK_FLAG_BLOCKED) - ? t('Channel has been unblocked') - : t('Channel has been blocked')) . EOL ); - else - notice(t('Unable to set address book parameters.') . EOL); - goaway($a->get_baseurl(true) . '/connections/' . $contact_id); - } - - if($cmd === 'ignore') { - if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_IGNORED)) - info((($orig_record[0]['abook_flags'] & ABOOK_FLAG_IGNORED) - ? t('Channel has been unignored') - : t('Channel has been ignored')) . EOL ); - else - notice(t('Unable to set address book parameters.') . EOL); - goaway($a->get_baseurl(true) . '/connections/' . $contact_id); - } - - if($cmd === 'archive') { - if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_ARCHIVED)) - info((($orig_record[0]['abook_flags'] & ABOOK_FLAG_ARCHIVED) - ? t('Channel has been unarchived') - : t('Channel has been archived')) . EOL ); - else - notice(t('Unable to set address book parameters.') . EOL); - goaway($a->get_baseurl(true) . '/connections/' . $contact_id); - } - - if($cmd === 'hide') { - if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_HIDDEN)) - info((($orig_record[0]['abook_flags'] & ABOOK_FLAG_HIDDEN) - ? t('Channel has been unhidden') - : t('Channel has been hidden')) . EOL ); - else - notice(t('Unable to set address book parameters.') . EOL); - goaway($a->get_baseurl(true) . '/connections/' . $contact_id); - } - - - if($cmd === 'drop') { - - require_once('include/Contact.php'); -// FIXME -// terminate_friendship($a->get_channel(),$orig_record[0]); - - contact_remove($orig_record[0]['abook_id']); - info( t('Contact has been removed.') . EOL ); - if(x($_SESSION,'return_url')) - goaway($a->get_baseurl(true) . '/' . $_SESSION['return_url']); - goaway($a->get_baseurl(true) . '/contacts'); - - } + if($new_friend) { + $arr = array('channel_id' => local_user(), 'abook' => $a->data['abook']); + call_hooks('accept_follow', $arr); } - if((x($a->data,'abook')) && (is_array($a->data['abook']))) { - - $contact_id = $a->data['abook']['abook_id']; - $contact = $a->data['abook']; + connections_clone($a); + return; - $tabs = array( - - array( - 'label' => t('View Profile'), - 'url' => $a->get_baseurl(true) . '/chanview/?f=&cid=' . $contact['abook_id'], - 'sel' => '', - 'title' => sprintf( t('View %s\'s profile'), $contact['xchan_name']), - ), - - array( - 'label' => t('Refresh Permissions'), - 'url' => $a->get_baseurl(true) . '/connections/' . $contact['abook_id'] . '/refresh', - 'sel' => '', - 'title' => t('Fetch updated permissions'), - ), - - array( - 'label' => (($contact['abook_flags'] & ABOOK_FLAG_BLOCKED) ? t('Unblock') : t('Block')), - 'url' => $a->get_baseurl(true) . '/connections/' . $contact['abook_id'] . '/block', - 'sel' => (($contact['abook_flags'] & ABOOK_FLAG_BLOCKED) ? 'active' : ''), - 'title' => t('Block or Unblock this connection'), - ), - - array( - 'label' => (($contact['abook_flags'] & ABOOK_FLAG_IGNORED) ? t('Unignore') : t('Ignore')), - 'url' => $a->get_baseurl(true) . '/connections/' . $contact['abook_id'] . '/ignore', - 'sel' => (($contact['abook_flags'] & ABOOK_FLAG_IGNORED) ? 'active' : ''), - 'title' => t('Ignore or Unignore this connection'), - ), - array( - 'label' => (($contact['abook_flags'] & ABOOK_FLAG_ARCHIVED) ? t('Unarchive') : t('Archive')), - 'url' => $a->get_baseurl(true) . '/connections/' . $contact['abook_id'] . '/archive', - 'sel' => (($contact['abook_flags'] & ABOOK_FLAG_ARCHIVED) ? 'active' : ''), - 'title' => t('Archive or Unarchive this connection'), - ), - array( - 'label' => (($contact['abook_flags'] & ABOOK_FLAG_HIDDEN) ? t('Unhide') : t('Hide')), - 'url' => $a->get_baseurl(true) . '/connections/' . $contact['abook_id'] . '/hide', - 'sel' => (($contact['abook_flags'] & ABOOK_FLAG_HIDDEN) ? 'active' : ''), - 'title' => t('Hide or Unhide this connection'), - ), - - array( - 'label' => t('Delete'), - 'url' => $a->get_baseurl(true) . '/connections/' . $contact['abook_id'] . '/drop', - 'sel' => '', - 'title' => t('Delete this connection'), - ), - - ); - - $tab_tpl = get_markup_template('common_tabs.tpl'); - $t = replace_macros($tab_tpl, array('$tabs'=>$tabs)); - - - - - $a->page['htmlhead'] .= replace_macros(get_markup_template('contact_head.tpl'), array( - '$baseurl' => $a->get_baseurl(true), - '$editselect' => $editselect, - )); - - require_once('include/contact_selectors.php'); - - $tpl = get_markup_template("abook_edit.tpl"); +} - if(feature_enabled(local_user(),'affinity')) { +function connections_clone(&$a) { - $slider_tpl = get_markup_template('contact_slider.tpl'); - $slide = replace_macros($slider_tpl,array( - '$me' => t('Me'), - '$val' => $contact['abook_closeness'], - '$intimate' => t('Best Friends'), - '$friends' => t('Friends'), - '$oldfriends' => t('Former Friends'), - '$acquaintances' => t('Acquaintances'), - '$world' => t('Unknown') - )); - } + if(! array_key_exists('abook',$a->data)) + return; + $clone = $a->data['abook']; - $perms = array(); - $channel = $a->get_channel(); + unset($clone['abook_id']); + unset($clone['abook_account']); + unset($clone['abook_channel']); - $global_perms = get_perms(); - $existing = get_all_perms(local_user(),$contact); + build_sync_packet(0 /* use the current local_user */, array('abook' => array($clone))); +} - foreach($global_perms as $k => $v) { - $perms[] = array('perms_' . $k, $v[3], (($contact['abook_their_perms'] & $v[1]) ? "1" : ""),((($contact['abook_my_perms'] & $v[1]) || $existing[$k]) ? "1" : ""), $v[1], (($channel[$v[0]] == PERMS_SPECIFIC) ? '' : '1'), $v[4]); - } +function connections_content(&$a) { + $sort_type = 0; + $o = ''; - $o .= replace_macros($tpl,array( - - '$header' => sprintf( t('Connections: settings for %s'),$contact['xchan_name']), - '$addr' => $contact['xchan_addr'], - '$viewprof' => t('View Profile'), - '$lbl_slider' => t('Slide to adjust your degree of friendship'), - '$slide' => $slide, - '$tabs' => $t, - '$tab_str' => $tab_str, - '$submit' => t('Submit'), - '$lbl_vis1' => t('Profile Visibility'), - '$lbl_vis2' => sprintf( t('Please choose the profile you would like to display to %s when viewing your profile securely.'), $contact['name']), - '$lbl_info1' => t('Contact Information / Notes'), - '$infedit' => t('Edit contact notes'), - '$close' => $contact['abook_closeness'], - '$them' => t('Their Settings'), - '$me' => t('My Settings'), - '$perms' => $perms, - '$full' => t('Full Sharing'), - '$cautious' => t('Cautious Sharing'), - '$follow' => t('Follow Only'), - '$advanced' => t('Advanced Permissions'), - '$quick' => t('Quick Links'), - '$common_link' => $a->get_baseurl(true) . '/common/loc/' . local_user() . '/' . $contact['id'], - '$all_friends' => $all_friends, - '$relation_text' => $relation_text, - '$visit' => sprintf( t('Visit %s\'s profile [%s]'),$contact['xchan_name'],$contact['xchan_url']), - '$blockunblock' => t('Block/Unblock contact'), - '$ignorecont' => t('Ignore contact'), - '$lblcrepair' => t("Repair URL settings"), - '$lblrecent' => t('View conversations'), - '$lblsuggest' => $lblsuggest, - '$delete' => t('Delete contact'), - '$poll_interval' => contact_poll_interval($contact['priority'],(! $poll_enabled)), - '$poll_enabled' => $poll_enabled, - '$lastupdtext' => t('Last update:'), - '$lost_contact' => $lost_contact, - '$updpub' => t('Update public posts'), - '$last_update' => $last_update, - '$udnow' => t('Update now'), -// '$profile_select' => contact_profile_assign($contact['profile_id'],(($contact['network'] !== NETWORK_DFRN) ? true : false)), - '$contact_id' => $contact['abook_id'], - '$block_text' => (($contact['blocked']) ? t('Unblock') : t('Block') ), - '$ignore_text' => (($contact['readonly']) ? t('Unignore') : t('Ignore') ), - '$blocked' => (($contact['blocked']) ? t('Currently blocked') : ''), - '$ignored' => (($contact['readonly']) ? t('Currently ignored') : ''), - '$archived' => (($contact['archive']) ? t('Currently archived') : ''), - '$hidden' => array('hidden', t('Hide this contact from others'), ($contact['hidden'] == 1), t('Replies/likes to your public posts <strong>may</strong> still be visible')), - '$photo' => $contact['photo'], - '$name' => $contact['name'], - '$dir_icon' => $dir_icon, - '$alt_text' => $alt_text, - '$sparkle' => $sparkle, - '$url' => $url - - )); - - $arr = array('contact' => $contact,'output' => $o); - - call_hooks('contact_edit', $arr); - - return $arr['output']; + if(! local_user()) { + notice( t('Permission denied.') . EOL); + return login(); } - $blocked = false; - $hidden = false; - $ignored = false; - $archived = false; - $unblocked = false; - $all = false; + $blocked = false; + $hidden = false; + $ignored = false; + $archived = false; + $unblocked = false; + $pending = false; + $unconnected = false; + $all = false; $_SESSION['return_url'] = $a->query_string; $search_flags = 0; + $head = ''; if(argc() == 2) { switch(argv(1)) { case 'blocked': $search_flags = ABOOK_FLAG_BLOCKED; + $head = t('Blocked'); $blocked = true; break; case 'ignored': $search_flags = ABOOK_FLAG_IGNORED; + $head = t('Ignored'); $ignored = true; break; case 'hidden': $search_flags = ABOOK_FLAG_HIDDEN; + $head = t('Hidden'); $hidden = true; break; case 'archived': $search_flags = ABOOK_FLAG_ARCHIVED; + $head = t('Archived'); $archived = true; break; + case 'pending': + $search_flags = ABOOK_FLAG_PENDING; + $head = t('New'); + $pending = true; + nav_set_selected('intros'); + break; + case 'ifpending': + $r = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and (abook_flags & %d) and not ((abook_flags & %d) or (xchan_flags & %d))", + intval(local_user()), + intval(ABOOK_FLAG_PENDING), + intval(ABOOK_FLAG_SELF|ABOOK_FLAG_IGNORED), + intval(XCHAN_FLAGS_DELETED|XCHAN_FLAGS_ORPHAN) + ); + if($r && $r[0]['total']) { + $search_flags = ABOOK_FLAG_PENDING; + $head = t('New'); + $pending = true; + nav_set_selected('intros'); + $a->argv[1] = 'pending'; + } + else { + $head = t('All'); + $search_flags = 0; + $all = true; + $a->argc = 1; + unset($a->argv[1]); + } + nav_set_selected('intros'); + break; + case 'unconnected': + $search_flags = ABOOK_FLAG_UNCONNECTED; + $head = t('Unconnected'); + $unconnected = true; + break; + case 'all': + $head = t('All'); default: $search_flags = 0; $all = true; @@ -433,7 +251,8 @@ function connections_content(&$a) { } $sql_extra = (($search_flags) ? " and ( abook_flags & " . $search_flags . " ) " : ""); - + if(argv(1) === 'pending') + $sql_extra .= " and not ( abook_flags & " . ABOOK_FLAG_IGNORED . " ) "; } else { @@ -446,51 +265,65 @@ function connections_content(&$a) { $tabs = array( array( 'label' => t('Suggestions'), - 'url' => $a->get_baseurl(true) . '/suggest', + 'url' => z_root() . '/suggest', 'sel' => '', 'title' => t('Suggest new connections'), ), array( + 'label' => t('New Connections'), + 'url' => z_root() . '/connections/pending', + 'sel' => ($pending) ? 'active' : '', + 'title' => t('Show pending (new) connections'), + ), + array( 'label' => t('All Connections'), - 'url' => $a->get_baseurl(true) . '/connections/all', + 'url' => z_root() . '/connections/all', 'sel' => ($all) ? 'active' : '', 'title' => t('Show all connections'), ), array( 'label' => t('Unblocked'), - 'url' => $a->get_baseurl(true) . '/connections', + 'url' => z_root() . '/connections', 'sel' => (($unblocked) && (! $search) && (! $nets)) ? 'active' : '', 'title' => t('Only show unblocked connections'), ), array( 'label' => t('Blocked'), - 'url' => $a->get_baseurl(true) . '/connections/blocked', + 'url' => z_root() . '/connections/blocked', 'sel' => ($blocked) ? 'active' : '', 'title' => t('Only show blocked connections'), ), array( 'label' => t('Ignored'), - 'url' => $a->get_baseurl(true) . '/connections/ignored', + 'url' => z_root() . '/connections/ignored', 'sel' => ($ignored) ? 'active' : '', 'title' => t('Only show ignored connections'), ), array( 'label' => t('Archived'), - 'url' => $a->get_baseurl(true) . '/connections/archived', + 'url' => z_root() . '/connections/archived', 'sel' => ($archived) ? 'active' : '', 'title' => t('Only show archived connections'), ), array( 'label' => t('Hidden'), - 'url' => $a->get_baseurl(true) . '/connections/hidden', + 'url' => z_root() . '/connections/hidden', 'sel' => ($hidden) ? 'active' : '', 'title' => t('Only show hidden connections'), ), + array( + 'label' => t('Unconnected'), + 'url' => z_root() . '/connections/unconnected', + 'sel' => ($unconnected) ? 'active' : '', + 'title' => t('Only show one-way connections'), + ), + + ); $tab_tpl = get_markup_template('common_tabs.tpl'); @@ -506,21 +339,21 @@ function connections_content(&$a) { $r = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash - where abook_channel = %d and not (abook_flags & %d) and not (abook_flags & %d) $sql_extra $sql_extra2 ", + where abook_channel = %d and not (abook_flags & %d) and not (xchan_flags & %d ) $sql_extra $sql_extra2 ", intval(local_user()), intval(ABOOK_FLAG_SELF), - intval(ABOOK_FLAG_PENDING) + intval(XCHAN_FLAGS_DELETED|XCHAN_FLAGS_ORPHAN) ); - if(count($r)) { + if($r) { $a->set_pager_total($r[0]['total']); $total = $r[0]['total']; } $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash - WHERE abook_channel = %d and not (abook_flags & %d) and not (abook_flags & %d) $sql_extra $sql_extra2 ORDER BY xchan_name LIMIT %d , %d ", + WHERE abook_channel = %d and not (abook_flags & %d) and not ( xchan_flags & %d) $sql_extra $sql_extra2 ORDER BY xchan_name LIMIT %d , %d ", intval(local_user()), intval(ABOOK_FLAG_SELF), - intval(ABOOK_FLAG_PENDING), + intval(XCHAN_FLAGS_DELETED|XCHAN_FLAGS_ORPHAN), intval($a->pager['start']), intval($a->pager['itemspage']) ); @@ -530,37 +363,34 @@ function connections_content(&$a) { if(count($r)) { foreach($r as $rr) { - - $contacts[] = array( - 'img_hover' => sprintf( t('%1$s [%2$s]'),$rr['xchan_name'],$rr['xchan_url']), - 'edit_hover' => t('Edit contact'), - 'photo_menu' => contact_photo_menu($rr), - 'id' => $rr['abook_id'], - 'alt_text' => $alt_text, - 'dir_icon' => $dir_icon, - 'thumb' => $rr['xchan_photo_m'], - 'name' => $rr['xchan_name'], - 'username' => $rr['xchan_name'], - 'sparkle' => $sparkle, - 'edit' => z_root() . '/connections/' . $rr['abook_id'], - 'url' => $rr['xchan_url'], - 'network' => network_to_name($rr['network']), - ); + if($rr['xchan_url']) { + $contacts[] = array( + 'img_hover' => sprintf( t('%1$s [%2$s]'),$rr['xchan_name'],$rr['xchan_url']), + 'edit_hover' => t('Edit contact'), + 'id' => $rr['abook_id'], + 'alt_text' => $alt_text, + 'dir_icon' => $dir_icon, + 'thumb' => $rr['xchan_photo_m'], + 'name' => $rr['xchan_name'], + 'username' => $rr['xchan_name'], + 'classes' => (($rr['abook_flags'] & ABOOK_FLAG_ARCHIVED) ? 'archived' : ''), + 'link' => z_root() . '/connedit/' . $rr['abook_id'], + 'url' => chanlink_url($rr['xchan_url']), + 'network' => network_to_name($rr['network']), + ); + } } - - - } - $tpl = get_markup_template("contacts-template.tpl"); - $o .= replace_macros($tpl,array( - '$header' => t('Connnections') . (($nets) ? ' - ' . network_to_name($nets) : ''), + $o .= replace_macros(get_markup_template('connections.tpl'),array( + '$header' => t('Connections') . (($head) ? ' - ' . $head : ''), '$tabs' => $t, '$total' => $total, '$search' => $search_hdr, - '$desc' => t('Search your connnections'), + '$desc' => t('Search your connections'), '$finding' => (($searching) ? t('Finding: ') . "'" . $search . "'" : ""), '$submit' => t('Find'), + '$edit' => t('Edit'), '$cmd' => $a->cmd, '$contacts' => $contacts, '$paginate' => paginate($a), diff --git a/mod/connedit.php b/mod/connedit.php new file mode 100644 index 000000000..61bb62766 --- /dev/null +++ b/mod/connedit.php @@ -0,0 +1,540 @@ +<?php + +/* @file connedit.php + * @brief In this file the connection-editor form is generated and evaluated. + * + * + */ + +require_once('include/Contact.php'); +require_once('include/socgraph.php'); +require_once('include/contact_selectors.php'); +require_once('include/group.php'); +require_once('include/contact_widgets.php'); +require_once('include/zot.php'); +require_once('include/widgets.php'); + +/* @brief Initialize the connection-editor + * + * + */ + +function connedit_init(&$a) { + + if(! local_user()) + return; + + if((argc() == 2) && intval(argv(1))) { + $r = q("SELECT abook.*, xchan.* + FROM abook left join xchan on abook_xchan = xchan_hash + WHERE abook_channel = %d and abook_id = %d LIMIT 1", + intval(local_user()), + intval(argv(1)) + ); + if($r) { + $a->poi = $r[0]; + } + } + + $channel = $a->get_channel(); + if($channel) + head_set_icon($channel['xchan_photo_s']); + +} + +/* @brief Evaluate posted values and set changes + * + */ + +function connedit_post(&$a) { + + if(! local_user()) + return; + + $contact_id = intval(argv(1)); + if(! $contact_id) + return; + + $orig_record = q("SELECT * FROM abook WHERE abook_id = %d AND abook_channel = %d LIMIT 1", + intval($contact_id), + intval(local_user()) + ); + + if(! $orig_record) { + notice( t('Could not access contact record.') . EOL); + goaway($a->get_baseurl(true) . '/connections'); + return; // NOTREACHED + } + + call_hooks('contact_edit_post', $_POST); + + $profile_id = $_POST['profile_assign']; + if($profile_id) { + $r = q("SELECT profile_guid FROM profile WHERE profile_guid = '%s' AND `uid` = %d LIMIT 1", + dbesc($profile_id), + intval(local_user()) + ); + if(! count($r)) { + notice( t('Could not locate selected profile.') . EOL); + return; + } + } + + $hidden = intval($_POST['hidden']); + + $priority = intval($_POST['poll']); + if($priority > 5 || $priority < 0) + $priority = 0; + + $closeness = intval($_POST['closeness']); + if($closeness < 0) + $closeness = 99; + + $abook_my_perms = 0; + + foreach($_POST as $k => $v) { + if(strpos($k,'perms_') === 0) { + $abook_my_perms += $v; + } + } + + $abook_flags = $orig_record[0]['abook_flags']; + $new_friend = false; + + + + if(($_REQUEST['pending']) && ($abook_flags & ABOOK_FLAG_PENDING)) { + $abook_flags = ( $abook_flags ^ ABOOK_FLAG_PENDING ); + $new_friend = true; + } + + $r = q("UPDATE abook SET abook_profile = '%s', abook_my_perms = %d , abook_closeness = %d, abook_flags = %d + where abook_id = %d AND abook_channel = %d LIMIT 1", + dbesc($profile_id), + intval($abook_my_perms), + intval($closeness), + intval($abook_flags), + intval($contact_id), + intval(local_user()) + ); + + if($orig_record[0]['abook_profile'] != $profile_id) { //Update profile photo permissions + + logger('As a new profile was assigned updateing profile photos'); + require_once('mod/profile_photo.php'); + profile_photo_set_profile_perms($profile_id); + + } + + + if($r) + info( t('Connection updated.') . EOL); + else + notice( t('Failed to update connection record.') . EOL); + + if($a->poi && $a->poi['abook_my_perms'] != $abook_my_perms + && (! ($a->poi['abook_flags'] & ABOOK_FLAG_SELF))) { + proc_run('php', 'include/notifier.php', 'permission_update', $contact_id); + } + + if($new_friend) { + $channel = $a->get_channel(); + $default_group = $channel['channel_default_group']; + if($default_group) { + require_once('include/group.php'); + $g = group_rec_byhash(local_user(),$default_group); + if($g) + group_add_member(local_user(),'',$a->poi['abook_xchan'],$g['id']); + } + + + + // Check if settings permit ("post new friend activity" is allowed, and + // friends in general or this friend in particular aren't hidden) + // and send out a new friend activity + // TODO + + // pull in a bit of content if there is any to pull in + proc_run('php','include/onepoll.php',$contact_id); + + } + + // Refresh the structure in memory with the new data + + $r = q("SELECT abook.*, xchan.* + FROM abook left join xchan on abook_xchan = xchan_hash + WHERE abook_channel = %d and abook_id = %d LIMIT 1", + intval(local_user()), + intval($contact_id) + ); + if($r) { + $a->poi = $r[0]; + } + + if($new_friend) { + $arr = array('channel_id' => local_user(), 'abook' => $a->poi); + call_hooks('accept_follow', $arr); + } + + connedit_clone($a); + + return; + +} + +/* @brief Clone connection + * + * + */ + +function connedit_clone(&$a) { + + if(! $a->poi) + return; + $clone = $a->poi; + + unset($clone['abook_id']); + unset($clone['abook_account']); + unset($clone['abook_channel']); + + build_sync_packet(0 /* use the current local_user */, array('abook' => array($clone))); +} + +/* @brief Generate content of connection edit page + * + * + */ + +function connedit_content(&$a) { + + $sort_type = 0; + $o = ''; + + // this triggers some javascript to set Full Sharing by default after + // completing a "follow" - which can be changed to something else before + // form submission, but this gives us something useable + + if($_GET['follow'] == 1) { + $o .= '<script>var after_following = 1;</script>'; + } + if(! local_user()) { + notice( t('Permission denied.') . EOL); + return login(); + } + + if(argc() == 3) { + + $contact_id = intval(argv(1)); + if(! $contact_id) + return; + + $cmd = argv(2); + + $orig_record = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash + WHERE abook_id = %d AND abook_channel = %d AND NOT ( abook_flags & %d ) and not ( abook_flags & %d ) LIMIT 1", + intval($contact_id), + intval(local_user()), + intval(ABOOK_FLAG_SELF), + // allow drop even if pending, just duplicate the self query + intval(($cmd === 'drop') ? ABOOK_FLAG_SELF : ABOOK_FLAG_PENDING) + ); + + if(! count($orig_record)) { + notice( t('Could not access address book record.') . EOL); + goaway($a->get_baseurl(true) . '/connections'); + } + + if($cmd === 'update') { + + // pull feed and consume it, which should subscribe to the hub. + proc_run('php',"include/poller.php","$contact_id"); + goaway($a->get_baseurl(true) . '/connedit/' . $contact_id); + + } + + if($cmd === 'refresh') { + if(! zot_refresh($orig_record[0],get_app()->get_channel())) + notice( t('Refresh failed - channel is currently unavailable.') ); + goaway($a->get_baseurl(true) . '/connedit/' . $contact_id); + } + + if($cmd === 'block') { + if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_BLOCKED)) { + info((($orig_record[0]['abook_flags'] & ABOOK_FLAG_BLOCKED) + ? t('Channel has been unblocked') + : t('Channel has been blocked')) . EOL ); + connedit_clone($a); + } + else + notice(t('Unable to set address book parameters.') . EOL); + goaway($a->get_baseurl(true) . '/connedit/' . $contact_id); + } + + if($cmd === 'ignore') { + if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_IGNORED)) { + info((($orig_record[0]['abook_flags'] & ABOOK_FLAG_IGNORED) + ? t('Channel has been unignored') + : t('Channel has been ignored')) . EOL ); + connedit_clone($a); + } + else + notice(t('Unable to set address book parameters.') . EOL); + goaway($a->get_baseurl(true) . '/connedit/' . $contact_id); + } + + if($cmd === 'archive') { + if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_ARCHIVED)) { + info((($orig_record[0]['abook_flags'] & ABOOK_FLAG_ARCHIVED) + ? t('Channel has been unarchived') + : t('Channel has been archived')) . EOL ); + connedit_clone($a); + } + else + notice(t('Unable to set address book parameters.') . EOL); + goaway($a->get_baseurl(true) . '/connedit/' . $contact_id); + } + + if($cmd === 'hide') { + if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_HIDDEN)) { + info((($orig_record[0]['abook_flags'] & ABOOK_FLAG_HIDDEN) + ? t('Channel has been unhidden') + : t('Channel has been hidden')) . EOL ); + connedit_clone($a); + } + else + notice(t('Unable to set address book parameters.') . EOL); + goaway($a->get_baseurl(true) . '/connedit/' . $contact_id); + } + + // We'll prevent somebody from unapproving a contact. + + if($cmd === 'approve') { + if($orig_record[0]['abook_flags'] & ABOOK_FLAG_PENDING) { + if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_PENDING)) { + info((($orig_record[0]['abook_flags'] & ABOOK_FLAG_PENDING) + ? t('Channel has been approved') + : t('Channel has been unapproved')) . EOL ); + connedit_clone($a); + } + else + notice(t('Unable to set address book parameters.') . EOL); + } + goaway($a->get_baseurl(true) . '/connedit/' . $contact_id); + } + + + if($cmd === 'drop') { + + require_once('include/Contact.php'); +// FIXME +// terminate_friendship($a->get_channel(),$orig_record[0]); + + contact_remove(local_user(), $orig_record[0]['abook_id']); +// FIXME - send to clones + info( t('Connection has been removed.') . EOL ); + if(x($_SESSION,'return_url')) + goaway($a->get_baseurl(true) . '/' . $_SESSION['return_url']); + goaway($a->get_baseurl(true) . '/contacts'); + + } + } + + if($a->poi) { + + $contact_id = $a->poi['abook_id']; + $contact = $a->poi; + + + $tabs = array( + + array( + 'label' => t('View Profile'), + 'url' => chanlink_cid($contact['abook_id']), + 'sel' => '', + 'title' => sprintf( t('View %s\'s profile'), $contact['xchan_name']), + ), + + array( + 'label' => t('Refresh Permissions'), + 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/refresh', + 'sel' => '', + 'title' => t('Fetch updated permissions'), + ), + + array( + 'label' => t('Recent Activity'), + 'url' => $a->get_baseurl(true) . '/network/?f=&cid=' . $contact['abook_id'], + 'sel' => '', + 'title' => t('View recent posts and comments'), + ), + + array( + 'label' => (($contact['abook_flags'] & ABOOK_FLAG_BLOCKED) ? t('Unblock') : t('Block')), + 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/block', + 'sel' => (($contact['abook_flags'] & ABOOK_FLAG_BLOCKED) ? 'active' : ''), + 'title' => t('Block or Unblock this connection'), + ), + + array( + 'label' => (($contact['abook_flags'] & ABOOK_FLAG_IGNORED) ? t('Unignore') : t('Ignore')), + 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/ignore', + 'sel' => (($contact['abook_flags'] & ABOOK_FLAG_IGNORED) ? 'active' : ''), + 'title' => t('Ignore or Unignore this connection'), + ), + array( + 'label' => (($contact['abook_flags'] & ABOOK_FLAG_ARCHIVED) ? t('Unarchive') : t('Archive')), + 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/archive', + 'sel' => (($contact['abook_flags'] & ABOOK_FLAG_ARCHIVED) ? 'active' : ''), + 'title' => t('Archive or Unarchive this connection'), + ), + array( + 'label' => (($contact['abook_flags'] & ABOOK_FLAG_HIDDEN) ? t('Unhide') : t('Hide')), + 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/hide', + 'sel' => (($contact['abook_flags'] & ABOOK_FLAG_HIDDEN) ? 'active' : ''), + 'title' => t('Hide or Unhide this connection'), + ), + + array( + 'label' => t('Delete'), + 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/drop', + 'sel' => '', + 'title' => t('Delete this connection'), + ), + + ); + + $self = false; + + if(! ($contact['abook_flags'] & ABOOK_FLAG_SELF)) { + $tab_tpl = get_markup_template('common_tabs.tpl'); + $t = replace_macros($tab_tpl, array('$tabs'=>$tabs)); + } + else + $self = true; + + $a->page['htmlhead'] .= replace_macros(get_markup_template('contact_head.tpl'), array( + '$baseurl' => $a->get_baseurl(true), + '$editselect' => $editselect + )); + + require_once('include/contact_selectors.php'); + + $tpl = get_markup_template("abook_edit.tpl"); + + if(feature_enabled(local_user(),'affinity')) { + + $slider_tpl = get_markup_template('contact_slider.tpl'); + $slide = replace_macros($slider_tpl,array( + '$me' => t('Me'), + '$val' => (($contact['abook_closeness']) ? $contact['abook_closeness'] : 99), + '$intimate' => t('Best Friends'), + '$friends' => t('Friends'), + '$oldfriends' => t('Former Friends'), + '$acquaintances' => t('Acquaintances'), + '$world' => t('Unknown') + )); + } + + $perms = array(); + $channel = $a->get_channel(); + + $global_perms = get_perms(); + $existing = get_all_perms(local_user(),$contact['abook_xchan']); + + $unapproved = array('pending', t('Approve this connection'), '', t('Accept connection to allow communication')); + + foreach($global_perms as $k => $v) { + $thisperm = (($contact['abook_my_perms'] & $v[1]) ? "1" : ''); + + // For auto permissions (when $self is true) we don't want to look at existing + // permissions because they are enabled for the channel owner + + if((! $self) && ($existing[$k])) + $thisperm = "1"; + + $perms[] = array('perms_' . $k, $v[3], (($contact['abook_their_perms'] & $v[1]) ? "1" : ""),$thisperm, $v[1], (($channel[$v[0]] == PERMS_SPECIFIC) ? '' : '1'), $v[4]); + } + + $o .= replace_macros($tpl,array( + + '$header' => (($self) ? t('Automatic Permissions Settings') : sprintf( t('Connections: settings for %s'),$contact['xchan_name'])), + '$addr' => $contact['xchan_addr'], + '$notself' => (($self) ? '' : '1'), + '$self' => (($self) ? '1' : ''), + '$autolbl' => t('When receiving a channel introduction, any permissions provided here will be applied to the new connection automatically and the introduction approved. Leave this page if you do not wish to use this feature.'), + '$viewprof' => t('View Profile'), + '$lbl_slider' => t('Slide to adjust your degree of friendship'), + '$slide' => $slide, + '$tabs' => $t, + '$tab_str' => $tab_str, + '$is_pending' => (($contact['abook_flags'] & ABOOK_FLAG_PENDING) ? 1 : ''), + '$unapproved' => $unapproved, + '$inherited' => t('inherited'), + '$approve' => t('Approve this connection'), + '$noperms' => (((! $self) && (! $contact['abook_my_perms'])) ? t('Connection has no individual permissions!') : ''), + '$noperm_desc' => (((! $self) && (! $contact['abook_my_perms'])) ? t('This may be appropriate based on your <a href="settings">privacy settings</a>, though you may wish to review the "Advanced Permissions".') : ''), + '$submit' => t('Submit'), + '$lbl_vis1' => t('Profile Visibility'), + '$lbl_vis2' => sprintf( t('Please choose the profile you would like to display to %s when viewing your profile securely.'), $contact['xchan_name']), + '$lbl_info1' => t('Contact Information / Notes'), + '$infedit' => t('Edit contact notes'), + '$close' => $contact['abook_closeness'], + '$them' => t('Their Settings'), + '$me' => t('My Settings'), + '$perms' => $perms, + '$clear' => t('Clear/Disable Automatic Permissions'), + '$forum' => t('Forum Members'), + '$soapbox' => t('Soapbox'), + '$full' => t('Full Sharing (typical social network permissions)'), + '$cautious' => t('Cautious Sharing '), + '$follow' => t('Follow Only'), + '$permlbl' => t('Individual Permissions'), + '$permnote' => t('Some permissions may be inherited from your channel <a href="settings">privacy settings</a>, which have higher priority than individual settings. Changing those inherited settings on this page will have no effect.'), + '$advanced' => t('Advanced Permissions'), + '$quick' => t('Simple Permissions (select one and submit)'), + '$common_link' => $a->get_baseurl(true) . '/common/loc/' . local_user() . '/' . $contact['id'], + '$all_friends' => $all_friends, + '$relation_text' => $relation_text, + '$visit' => sprintf( t('Visit %s\'s profile - %s'),$contact['xchan_name'],$contact['xchan_url']), + '$blockunblock' => t('Block/Unblock contact'), + '$ignorecont' => t('Ignore contact'), + '$lblcrepair' => t("Repair URL settings"), + '$lblrecent' => t('View conversations'), + '$lblsuggest' => $lblsuggest, + '$delete' => t('Delete contact'), + '$poll_interval' => contact_poll_interval($contact['priority'],(! $poll_enabled)), + '$poll_enabled' => $poll_enabled, + '$lastupdtext' => t('Last update:'), + '$lost_contact' => $lost_contact, + '$updpub' => t('Update public posts'), + '$last_update' => relative_date($contact['abook_connected']), + '$udnow' => t('Update now'), + '$profile_select' => contact_profile_assign($contact['abook_profile']), + '$multiprofs' => feature_enabled(local_user(),'multi_profiles'), + '$contact_id' => $contact['abook_id'], + '$block_text' => (($contact['blocked']) ? t('Unblock') : t('Block') ), + '$ignore_text' => (($contact['readonly']) ? t('Unignore') : t('Ignore') ), + '$blocked' => (($contact['blocked']) ? t('Currently blocked') : ''), + '$ignored' => (($contact['readonly']) ? t('Currently ignored') : ''), + '$archived' => (($contact['archive']) ? t('Currently archived') : ''), + '$pending' => (($contact['archive']) ? t('Currently pending') : ''), + '$hidden' => array('hidden', t('Hide this contact from others'), ($contact['hidden'] == 1), t('Replies/likes to your public posts <strong>may</strong> still be visible')), + '$photo' => $contact['photo'], + '$name' => $contact['name'], + '$dir_icon' => $dir_icon, + '$alt_text' => $alt_text, + '$sparkle' => $sparkle, + '$url' => $url + + )); + + $arr = array('contact' => $contact,'output' => $o); + + call_hooks('contact_edit', $arr); + + return $arr['output']; + + } + + +} diff --git a/mod/contactgroup.php b/mod/contactgroup.php index bf81afe07..8b23f9f10 100644 --- a/mod/contactgroup.php +++ b/mod/contactgroup.php @@ -4,27 +4,27 @@ require_once('include/group.php'); function contactgroup_content(&$a) { - if(! local_user()) { killme(); } - if(($a->argc > 2) && intval($a->argv[1]) && intval($a->argv[2])) { - $r = q("SELECT `id` FROM `contact` WHERE `id` = %d AND `uid` = %d and `self` = 0 and `blocked` = 0 AND `pending` = 0 LIMIT 1", - intval($a->argv[2]), - intval(local_user()) + if((argc() > 2) && (intval(argv(1))) && (argv(2))) { + $r = q("SELECT abook_xchan from abook where abook_xchan = '%s' and abook_channel = %d and not ( abook_flags & %d ) limit 1", + dbesc(argv(2)), + intval(local_user()), + intval(ABOOK_FLAG_SELF) ); - if(count($r)) - $change = intval($a->argv[2]); + if($r) + $change = $r[0]['abook_xchan']; } - if(($a->argc > 1) && (intval($a->argv[1]))) { + if((argc() > 1) && (intval(argv(1)))) { - $r = q("SELECT * FROM `group` WHERE `id` = %d AND `uid` = %d AND `deleted` = 0 LIMIT 1", - intval($a->argv[1]), + $r = q("SELECT * FROM `groups` WHERE `id` = %d AND `uid` = %d AND `deleted` = 0 LIMIT 1", + intval(argv(1)), intval(local_user()) ); - if(! count($r)) { + if(! $r) { killme(); } @@ -33,7 +33,7 @@ function contactgroup_content(&$a) { $preselected = array(); if(count($members)) { foreach($members as $member) - $preselected[] = $member['id']; + $preselected[] = $member['xchan_hash']; } if($change) { diff --git a/mod/crepair.php b/mod/crepair.php deleted file mode 100644 index e5ece0f98..000000000 --- a/mod/crepair.php +++ /dev/null @@ -1,171 +0,0 @@ -<?php - -function crepair_init(&$a) { - if(! local_user()) - return; - - $contact_id = 0; - - if(($a->argc == 2) && intval($a->argv[1])) { - $contact_id = intval($a->argv[1]); - $r = q("SELECT * FROM `contact` WHERE `uid` = %d and `id` = %d LIMIT 1", - intval(local_user()), - intval($contact_id) - ); - if(! count($r)) { - $contact_id = 0; - } - } - - if(! x($a->page,'aside')) - $a->page['aside'] = ''; - - if($contact_id) { - $a->data['contact'] = $r[0]; - $o .= '<div class="vcard">'; - $o .= '<div class="fn">' . $a->data['contact']['name'] . '</div>'; - $o .= '<div id="profile-photo-wrapper"><img class="photo" style="width: 175px; height: 175px;" src="' . $a->data['contact']['photo'] . '" alt="' . $a->data['contact']['name'] . '" /></div>'; - $o .= '</div>'; - $a->page['aside'] .= $o; - - } -} - - -function crepair_post(&$a) { - if(! local_user()) - return; - - $cid = (($a->argc > 1) ? intval($a->argv[1]) : 0); - - if($cid) { - $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($cid), - intval(local_user()) - ); - } - - if(! count($r)) - return; - - $contact = $r[0]; - - $name = ((x($_POST,'name')) ? $_POST['name'] : $contact['name']); - $nick = ((x($_POST,'nick')) ? $_POST['nick'] : ''); - $url = ((x($_POST,'url')) ? $_POST['url'] : ''); - $request = ((x($_POST,'request')) ? $_POST['request'] : ''); - $confirm = ((x($_POST,'confirm')) ? $_POST['confirm'] : ''); - $notify = ((x($_POST,'notify')) ? $_POST['notify'] : ''); - $poll = ((x($_POST,'poll')) ? $_POST['poll'] : ''); - $attag = ((x($_POST,'attag')) ? $_POST['attag'] : ''); - $photo = ((x($_POST,'photo')) ? $_POST['photo'] : ''); - - $r = q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `url` = '%s', `request` = '%s', `confirm` = '%s', `notify` = '%s', `poll` = '%s', `attag` = '%s' - WHERE `id` = %d AND `uid` = %d LIMIT 1", - dbesc($name), - dbesc($nick), - dbesc($url), - dbesc($request), - dbesc($confirm), - dbesc($notify), - dbesc($poll), - dbesc($attag), - intval($contact['id']), - local_user() - ); - - if($photo) { - logger('mod-crepair: updating photo from ' . $photo); - require_once("Photo.php"); - - $photos = import_profile_photo($photo,local_user(),$contact['id']); - - $x = q("UPDATE `contact` SET `photo` = '%s', - `thumb` = '%s', - `micro` = '%s', - `name_date` = '%s', - `uri_date` = '%s', - `avatar_date` = '%s' - WHERE `id` = %d LIMIT 1 - ", - dbesc($photos[0]), - dbesc($photos[1]), - dbesc($photos[2]), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - intval($contact['id']) - ); - } - - if($r) - info( t('Contact settings applied.') . EOL); - else - notice( t('Contact update failed.') . EOL); - - - return; -} - - - -function crepair_content(&$a) { - - if(! local_user()) { - notice( t('Permission denied.') . EOL); - return; - } - - $cid = (($a->argc > 1) ? intval($a->argv[1]) : 0); - - if($cid) { - $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($cid), - intval(local_user()) - ); - } - - if(! count($r)) { - notice( t('Contact not found.') . EOL); - return; - } - - $contact = $r[0]; - - $msg1 = t('Repair Contact Settings'); - - $msg2 = t('<strong>WARNING: This is highly advanced</strong> and if you enter incorrect information your communications with this contact may stop working.'); - $msg3 = t('Please use your browser \'Back\' button <strong>now</strong> if you are uncertain what to do on this page.'); - - $o .= '<h2>' . $msg1 . '</h2>'; - - $o .= '<div class="error-message">' . $msg2 . EOL . EOL. $msg3 . '</div>'; - - $o .= EOL . '<a href="contacts/' . $cid . '">' . t('Return to contact editor') . '</a>' . EOL; - - $tpl = get_markup_template('crepair.tpl'); - $o .= replace_macros($tpl, array( - '$label_name' => t('Name'), - '$label_nick' => t('Account Nickname'), - '$label_attag' => t('@Tagname - overrides Name/Nickname'), - '$label_url' => t('Account URL'), - '$label_request' => t('Friend Request URL'), - '$label_confirm' => t('Friend Confirm URL'), - '$label_notify' => t('Notification Endpoint URL'), - '$label_poll' => t('Poll/Feed URL'), - '$label_photo' => t('New photo from this URL'), - '$contact_name' => $contact['name'], - '$contact_nick' => $contact['nick'], - '$contact_id' => $contact['id'], - '$contact_url' => $contact['url'], - '$request' => $contact['request'], - '$confirm' => $contact['confirm'], - '$notify' => $contact['notify'], - '$poll' => $contact['poll'], - '$contact_attag' => $contact['attag'], - '$lbl_submit' => t('Submit') - )); - - return $o; - -} diff --git a/mod/directory.php b/mod/directory.php index c9332f447..b11b0d410 100644 --- a/mod/directory.php +++ b/mod/directory.php @@ -1,22 +1,14 @@ <?php require_once('include/dir_fns.php'); +require_once('include/widgets.php'); function directory_init(&$a) { - $a->set_pager_itemspage(60); + $a->set_pager_itemspage(80); } -function directory_aside(&$a) { - - if(local_user()) { - require_once('include/contact_widgets.php'); - $a->set_widget('find_people',findpeople_widget()); - } -} - - function directory_content(&$a) { if((get_config('system','block_public')) && (! local_user()) && (! remote_user())) { @@ -24,6 +16,24 @@ function directory_content(&$a) { return; } + $safe_mode = 1; + + $observer = get_observer_hash(); + + if($observer) { + $safe_mode = get_xconfig($observer,'directory','safe_mode'); + } + if($safe_mode === false) + $safe_mode = 1; + else + $safe_mode = intval($safe_mode); + + if(x($_REQUEST,'safe')) + $safe_mode = (intval($_REQUEST['safe'])); + + + + $o = ''; nav_set_selected('directory'); @@ -32,154 +42,188 @@ function directory_content(&$a) { else $search = ((x($_GET,'search')) ? notags(trim(rawurldecode($_GET['search']))) : ''); + $advanced = ((x($_REQUEST,'query')) ? notags(trim($_REQUEST['query'])) : ''); - $tpl = get_markup_template('directory_header.tpl'); + $keywords = (($_GET['keywords']) ? $_GET['keywords'] : ''); + $tpl = get_markup_template('directory_header.tpl'); + $dirmode = intval(get_config('system','directory_mode')); -// if(($dirmode == DIRECTORY_MODE_PRIMARY) || ($dirmode == DIRECTORY_MODE_STANDALONE)) { -// $localdir = true; -// return; -// } - -// FIXME -$localdir = true; + if(($dirmode == DIRECTORY_MODE_PRIMARY) || ($dirmode == DIRECTORY_MODE_STANDALONE)) { + $url = z_root() . '/dirsearch'; + } + if(! $url) { + $directory = find_upstream_directory($dirmode); + $url = $directory['url'] . '/dirsearch'; + } + logger('mod_directory: URL = ' . $url, LOGGER_DEBUG); - if(! $localdir) { - $directory = find_upstream_directory($dirmode); + $contacts = array(); - if($directory) { - $url = $directory['url']; - } - else { - $url = DIRECTORY_FALLBACK_MASTER . '/post'; + if(local_user()) { + $x = q("select abook_xchan from abook where abook_channel = %d", + intval(local_user()) + ); + if($x) { + foreach($x as $xx) + $contacts[] = $xx['abook_xchan']; } } - if($localdir) { - if($search) - $search = dbesc($search); - $sql_extra = ((strlen($search)) ? " AND MATCH ( xchan_name, xchan_addr, xprof_desc, xprof_locale, xprof_region, xprof_country, xprof_gender, xprof_marital ) AGAINST ('$search' IN BOOLEAN MODE) " : ""); - - // group_concat(xtag_term separator ', ') as tags - $r = q("SELECT COUNT(xchan_hash) AS `total` FROM xchan left join xprof on xchan_hash = xprof_hash $sql_extra"); - if($r) - $a->set_pager_total($r[0]['total']); - - $order = " ORDER BY `xchan_name` ASC "; + if($url) { + // We might want to make the tagadelic count (&kw=) configurable or turn it off completely. + $numtags = get_config('system','directorytags'); - $r = q("SELECT xchan.*, xprof.* from xchan left join xprof on xchan_hash = xprof_hash $sql_extra $order LIMIT %d , %d ", - intval($a->pager['start']), - intval($a->pager['itemspage']) - ); + $kw = ((intval($numtags)) ? $numtags : 24); + $query = $url . '?f=&kw=' . $kw . (($safe_mode != 1) ? '&safe=' . $safe_mode : ''); + if($search) + $query .= '&name=' . urlencode($search) . '&keywords=' . urlencode($search); + if(strpos($search,'@')) + $query .= '&address=' . urlencode($search); + if($keywords) + $query .= '&keywords=' . urlencode($keywords); + if($advanced) + $query .= '&query=' . urlencode($advanced); - if($r) { + $sort_order = ((x($_REQUEST,'order')) ? $_REQUEST['order'] : ''); + if($sort_order) + $query .= '&order=' . urlencode($sort_order); - $entries = array(); + if($a->pager['page'] != 1) + $query .= '&p=' . $a->pager['page']; - $photo = 'thumb'; + logger('mod_directory: query: ' . $query); - foreach($r as $rr) { + $x = z_fetch_url($query); + logger('directory: return from upstream: ' . print_r($x,true), LOGGER_DATA); - $profile_link = chanlink_hash($rr['xchan_hash']); - - $pdesc = (($rr['xprof_desc']) ? $rr['xprof_desc'] . '<br />' : ''); - - $details = ''; - if(strlen($rr['xprof_locale'])) - $details .= $rr['xprof_locale']; - if(strlen($rr['xprof_region'])) { - if(strlen($rr['xprof_locale'])) - $details .= ', '; - $details .= $rr['xprof_region']; - } - if(strlen($rr['xprof_country'])) { - if(strlen($details)) - $details .= ', '; - $details .= $rr['xprof_country']; - } - if(strlen($rr['xprof_dob'])) { - if(($years = age($rr['xprof_dob'],'UTC','')) != 0) - $details .= '<br />' . t('Age: ') . $years ; - } - if(strlen($rr['xprof_gender'])) - $details .= '<br />' . t('Gender: ') . $rr['xprof_gender']; + if($x['success']) { + $t = 0; + $j = json_decode($x['body'],true); + if($j) { - $page_type = ''; + if($j['results']) { - $profile = $rr; + $entries = array(); - if ((x($profile,'xprof_locale') == 1) - || (x($profile,'xprof_region') == 1) - || (x($profile,'xprof_postcode') == 1) - || (x($profile,'xprof_country') == 1)) - $location = t('Location:'); + $photo = 'thumb'; - $gender = ((x($profile,'xprof_gender') == 1) ? t('Gender:') : False); + foreach($j['results'] as $rr) { - $marital = ((x($profile,'marital') == 1) ? t('Status:') : False); + $profile_link = chanlink_url($rr['url']); + + $pdesc = (($rr['description']) ? $rr['description'] . '<br />' : ''); + $connect_link = ((local_user()) ? z_root() . '/follow?f=&url=' . urlencode($rr['address']) : ''); + + if(in_array($rr['hash'],$contacts)) + $connect_link = ''; + + $details = ''; + if(strlen($rr['locale'])) + $details .= $rr['locale']; + if(strlen($rr['region'])) { + if(strlen($rr['locale'])) + $details .= ', '; + $details .= $rr['region']; + } + if(strlen($rr['country'])) { + if(strlen($details)) + $details .= ', '; + $details .= $rr['country']; + } + if(strlen($rr['birthday'])) { + if(($years = age($rr['birthday'],'UTC','')) != 0) + $details .= '<br />' . t('Age: ') . $years ; + } + if(strlen($rr['gender'])) + $details .= '<br />' . t('Gender: ') . $rr['gender']; + + $page_type = ''; + + $profile = $rr; + + if ((x($profile,'locale') == 1) + || (x($profile,'region') == 1) + || (x($profile,'postcode') == 1) + || (x($profile,'country') == 1)) + $location = t('Location:'); + + $gender = ((x($profile,'gender') == 1) ? t('Gender:') : False); - $homepage = ((x($profile,'homepage') == 1) ? t('Homepage:') : False); + $marital = ((x($profile,'marital') == 1) ? t('Status:') : False); + + $homepage = ((x($profile,'homepage') == 1) ? t('Homepage:') : False); - $about = ((x($profile,'about') == 1) ? t('About:') : False); - - $t = 0; - - $entry = array( - 'id' => ++$t, - 'profile_link' => $profile_link, - 'photo' => $rr[xchan_photo_m], - 'alttext' => $rr['xchan_name'], - 'name' => $rr['xchan_name'], - 'details' => $pdesc . $details, - 'profile' => $profile, - 'location' => $location, - 'gender' => $gender, - 'pdesc' => $pdesc, - 'marital' => $marital, - 'homepage' => $homepage, - 'about' => $about, - - ); - - $arr = array('contact' => $rr, 'entry' => $entry); - - call_hooks('directory_item', $arr); + $about = ((x($profile,'about') == 1) ? t('About:') : False); - unset($profile); - unset($location); - $entries[] = $entry; + $entry = array( + 'id' => ++$t, + 'profile_link' => $profile_link, + 'photo' => $rr['photo'], + 'hash' => $rr['hash'], + 'alttext' => $rr['name'] . ' ' . $rr['address'], + 'name' => $rr['name'], + 'details' => $pdesc . $details, + 'profile' => $profile, + 'address' => $rr['address'], + 'location' => $location, + 'gender' => $gender, + 'pdesc' => $pdesc, + 'marital' => $marital, + 'homepage' => $homepage, + 'about' => $about, + 'conn_label' => t('Connect'), + 'connect' => $connect_link, + ); + + $arr = array('contact' => $rr, 'entry' => $entry); + + call_hooks('directory_item', $arr); + + $entries[] = $arr['entry']; + unset($profile); + unset($location); - } - logger('entries: ' . print_r($entries,true)); + } - $o .= replace_macros($tpl, array( - '$search' => $search, - '$desc' => t('Find'), - '$finddsc' => t('Finding:'), - '$safetxt' => htmlspecialchars($search,ENT_QUOTES,'UTF-8'), - '$entries' => $entries, - '$dirlbl' => t('Directory'), - '$submit' => t('Find') - )); + if($j['keywords']) { + $a->data['directory_keywords'] = $j['keywords']; + } +// logger('mod_directory: entries: ' . print_r($entries,true), LOGGER_DATA); - $o .= paginate($a); + $o .= replace_macros($tpl, array( + '$search' => $search, + '$desc' => t('Find'), + '$finddsc' => t('Finding:'), + '$safetxt' => htmlspecialchars($search,ENT_QUOTES,'UTF-8'), + '$entries' => $entries, + '$dirlbl' => t('Directory'), + '$submit' => t('Find') + )); - } - else - info( t("No entries (some entries may be hidden).") . EOL); + $o .= alt_pager($a,$j['records'], t('next page'), t('previous page')); + } + else { + if($a->pager['page'] == 1 && $j['records'] == 0 && strpos($search,'@')) { + goaway(z_root() . '/chanview/?f=&address=' . $search); + } + info( t("No entries (some entries may be hidden).") . EOL); + } + } + } } - return $o; } + diff --git a/mod/dirfind.php b/mod/dirfind.php deleted file mode 100644 index 54bbf31af..000000000 --- a/mod/dirfind.php +++ /dev/null @@ -1,68 +0,0 @@ -<?php - -function dirfind_init(&$a) { - - require_once('include/contact_widgets.php'); - - if(! x($a->page,'aside')) - $a->page['aside'] = ''; - - $a->page['aside'] .= follow_widget(); - - $a->page['aside'] .= findpeople_widget(); -} - - - -function dirfind_content(&$a) { - - $search = notags(trim($_REQUEST['search'])); - - if(strpos($search,'@') === 0) - $search = substr($search,1); - - $o = ''; - - $o .= '<h2>' . t('People Search') . ' - ' . $search . '</h2>'; - - if($search) { - - $p = (($a->pager['page'] != 1) ? '&p=' . $a->pager['page'] : ''); - - if(strlen(get_config('system','directory_submit_url'))) - $x = fetch_url('http://dir.friendica.com/lsearch?f=' . $p . '&search=' . urlencode($search)); - -//TODO fallback local search if global dir not available. -// else -// $x = post_url($a->get_baseurl() . '/lsearch', $params); - - $j = json_decode($x); - - if($j->total) { - $a->set_pager_total($j->total); - $a->set_pager_itemspage($j->items_page); - } - - if(count($j->results)) { - - $tpl = get_markup_template('match.tpl'); - foreach($j->results as $jj) { - - $o .= replace_macros($tpl,array( - '$url' => zid($jj->url), - '$name' => $jj->name, - '$photo' => $jj->photo, - '$tags' => $jj->tags - )); - } - } - else { - info( t('No matches') . EOL); - } - - } - - $o .= '<div class="clear"></div>'; - $o .= paginate($a); - return $o; -} diff --git a/mod/dirprofile.php b/mod/dirprofile.php new file mode 100644 index 000000000..e9b12ada7 --- /dev/null +++ b/mod/dirprofile.php @@ -0,0 +1,184 @@ +<?php + +require_once('include/dir_fns.php'); +require_once('include/bbcode.php'); + +function dirprofile_init(&$a) { + + if((get_config('system','block_public')) && (! local_user()) && (! remote_user())) { + notice( t('Public access denied.') . EOL); + return; + } + + $hash = $_REQUEST['hash']; + if(! $hash) + return ''; + + $o = ''; + + $dirmode = intval(get_config('system','directory_mode')); + + if(($dirmode == DIRECTORY_MODE_PRIMARY) || ($dirmode == DIRECTORY_MODE_STANDALONE)) { + $url = z_root() . '/dirsearch'; + } + if(! $url) { + $directory = find_upstream_directory($dirmode); + $url = $directory['url'] . '/dirsearch'; + } + logger('mod_directory: URL = ' . $url, LOGGER_DEBUG); + + $contacts = array(); + + if(local_user()) { + $x = q("select abook_xchan from abook where abook_channel = %d", + intval(local_user()) + ); + if($x) { + foreach($x as $xx) + $contacts[] = $xx['abook_xchan']; + } + } + + + + if($url) { + + $query = $url . '?f=&hash=' . $hash; + + $x = z_fetch_url($query); + logger('dirprofile: return from upstream: ' . print_r($x,true), LOGGER_DATA); + + if($x['success']) { + $t = 0; + $j = json_decode($x['body'],true); + if($j) { + + if($j['results']) { + + $entries = array(); + + $photo = 'thumb'; + + foreach($j['results'] as $rr) { + + $profile_link = chanlink_url($rr['url']); + + $pdesc = (($rr['description']) ? $rr['description'] . '<br />' : ''); + + $qrlink = zid($rr['url']); + $connect_link = ((local_user()) ? z_root() . '/follow?f=&url=' . urlencode($rr['address']) : ''); + + $online = remote_online_status($rr['address']); + + + if(in_array($rr['hash'],$contacts)) + $connect_link = ''; + + $details = ''; + if(strlen($rr['locale'])) + $details .= $rr['locale']; + if(strlen($rr['region'])) { + if(strlen($rr['locale'])) + $details .= ', '; + $details .= $rr['region']; + } + if(strlen($rr['country'])) { + if(strlen($details)) + $details .= ', '; + $details .= $rr['country']; + } + if(strlen($rr['birthday'])) { + if(($years = age($rr['birthday'],'UTC','')) != 0) + $details .= '<br />' . t('Age: ') . $years ; + } + if(strlen($rr['gender'])) + $details .= '<br />' . t('Gender: ') . $rr['gender']; + + $page_type = ''; + + $profile = $rr; + + if ((x($profile,'locale') == 1) + || (x($profile,'region') == 1) + || (x($profile,'postcode') == 1) + || (x($profile,'country') == 1)) + $location = t('Location:'); + + + $marital = ((x($profile,'marital') == 1) ? t('Status: ') . $profile['marital'] : False); + $sexual = ((x($profile,'sexual') == 1) ? t('Sexual Preference: ') . $profile['sexual'] : False); + + $homepage = ((x($profile,'homepage') == 1) ? t('Homepage: ') . linkify($profile['homepage']) : False); + $hometown = ((x($profile,'hometown') == 1) ? t('Hometown: ') . $profile['hometown'] : False); + + $about = ((x($profile,'about') == 1) ? t('About: ') . bbcode($profile['about']) : False); + + $keywords = ((x($profile,'keywords')) ? $profile['keywords'] : ''); + if($keywords) { + $keywords = str_replace(',',' ', $keywords); + $keywords = str_replace(' ',' ', $keywords); + $karr = explode(' ', $keywords); + $out = ''; + if($karr) { + if(local_user()) { + $r = q("select keywords from profile where uid = %d and is_default = 1 limit 1", + intval(local_user()) + ); + if($r) { + $keywords = str_replace(',',' ', $r[0]['keywords']); + $keywords = str_replace(' ',' ', $keywords); + $marr = explode(' ', $keywords); + } + } + foreach($karr as $k) { + if(strlen($out)) + $out .= ', '; + if($marr && in_arrayi($k,$marr)) + $out .= '<strong>' . $k . '</strong>'; + else + $out .= $k; + } + } + + } + $entry = replace_macros(get_markup_template('direntry_large.tpl'), array( + '$id' => ++$t, + '$profile_link' => $profile_link, + '$qrlink' => $qrlink, + '$photo' => $rr['photo_l'], + '$alttext' => $rr['name'] . ' ' . $rr['address'], + '$name' => $rr['name'], + '$online' => (($online) ? t('Online Now') : ''), + '$details' => $pdesc . $details, + '$profile' => $profile, + '$address' => $rr['address'], + '$location' => $location, + '$gender' => $gender, + '$pdesc' => $pdesc, + '$marital' => $marital, + '$homepage' => $homepage, + '$hometown' => $hometown, + '$about' => $about, + '$kw' => (($out) ? t('Keywords: ') : ''), + '$keywords' => $out, + '$conn_label' => t('Connect'), + '$connect' => $connect_link, + )); + + + echo $entry; + killme(); + + } + } + else { + info( t("Not found.") . EOL); + } + } + } + } + + + + +}
\ No newline at end of file diff --git a/mod/dirsearch.php b/mod/dirsearch.php index 30a1fadae..0ace4ecae 100644 --- a/mod/dirsearch.php +++ b/mod/dirsearch.php @@ -4,7 +4,7 @@ require_once('include/dir_fns.php'); function dirsearch_init(&$a) { - $a->set_pager_itemspage(60); + $a->set_pager_itemspage(80); } @@ -14,70 +14,197 @@ function dirsearch_content(&$a) { // If you've got a public directory server, you probably shouldn't block public access - if((get_config('system','block_public')) && (! local_user()) && (! remote_user())) { - $ret['message'] = t('Public access denied.'); - return; - } $dirmode = intval(get_config('system','directory_mode')); if($dirmode == DIRECTORY_MODE_NORMAL) { $ret['message'] = t('This site is not a directory server'); - return; + json_return_and_die($ret); + } + + if(argc() > 1 && argv(1) === 'sites') { + $ret = list_public_sites(); + json_return_and_die($ret); + } + + $sql_extra = ''; + + $tables = array('name','address','locale','region','postcode','country','gender','marital','sexual','keywords'); + + if($_REQUEST['query']) { + $advanced = dir_parse_query($_REQUEST['query']); + if($advanced) { + foreach($advanced as $adv) { + if(in_array($adv['field'],$tables)) { + if($adv['field'] === 'name') + $sql_extra .= dir_query_build($adv['logic'],'xchan_name',$adv['value']); + elseif($adv['field'] === 'address') + $sql_extra .= dir_query_build($adv['logic'],'xchan_addr',$adv['value']); + else + $sql_extra .= dir_query_build($adv['logic'],'xprof_' . $adv['field'],$adv['value']); + } + } + } } - $name = ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''); - $address = ((x($_REQUEST,'address')) ? $_REQUEST['address'] : ''); - $locale = ((x($_REQUEST,'locale')) ? $_REQUEST['locale'] : ''); - $region = ((x($_REQUEST,'region')) ? $_REQUEST['region'] : ''); + $hash = ((x($_REQUEST['hash'])) ? $_REQUEST['hash'] : ''); + + $name = ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''); + $hub = ((x($_REQUEST,'hub')) ? $_REQUEST['hub'] : ''); + $address = ((x($_REQUEST,'address')) ? $_REQUEST['address'] : ''); + $locale = ((x($_REQUEST,'locale')) ? $_REQUEST['locale'] : ''); + $region = ((x($_REQUEST,'region')) ? $_REQUEST['region'] : ''); $postcode = ((x($_REQUEST,'postcode')) ? $_REQUEST['postcode'] : ''); - $country = ((x($_REQUEST,'country')) ? $_REQUEST['country'] : ''); - $gender = ((x($_REQUEST,'gender')) ? $_REQUEST['gender'] : ''); - $marital = ((x($_REQUEST,'marital')) ? $_REQUEST['marital'] : ''); + $country = ((x($_REQUEST,'country')) ? $_REQUEST['country'] : ''); + $gender = ((x($_REQUEST,'gender')) ? $_REQUEST['gender'] : ''); + $marital = ((x($_REQUEST,'marital')) ? $_REQUEST['marital'] : ''); + $sexual = ((x($_REQUEST,'sexual')) ? $_REQUEST['sexual'] : ''); $keywords = ((x($_REQUEST,'keywords')) ? $_REQUEST['keywords'] : ''); + $agege = ((x($_REQUEST,'agege')) ? intval($_REQUEST['agege']) : 0 ); + $agele = ((x($_REQUEST,'agele')) ? intval($_REQUEST['agele']) : 0 ); + $kw = ((x($_REQUEST,'kw')) ? intval($_REQUEST['kw']) : 0 ); + // by default use a safe search + $safe = ((x($_REQUEST,'safe'))); // ? intval($_REQUEST['safe']) : 1 ); + if ($safe === false) + $safe = 1; + + if(array_key_exists('sync',$_REQUEST)) { + if($_REQUEST['sync']) + $sync = datetime_convert('UTC','UTC',$_REQUEST['sync']); + else + $sync = datetime_convert('UTC','UTC','2010-01-01 01:01:00'); + } + else + $sync = false; - $sql_extra = ''; + $sort_order = ((x($_REQUEST,'order')) ? $_REQUEST['order'] : ''); + + $joiner = ' OR '; + if($_REQUEST['and']) + $joiner = ' AND '; if($name) - $sql_extra .= " AND xchan_name like '" . protect_sprintf( '%' . dbesc($name) . '%' ) . "' "; - if($addr) - $sql_extra .= " AND xchan_addr like '" . protect_sprintf( '%' . dbesc($addr) . '%' ) . "' "; + $sql_extra .= dir_query_build($joiner,'xchan_name',$name); + if($hub) + $sql_extra .= " $joiner xchan_hash in (select hubloc_hash from hubloc where hubloc_host = '" . protect_sprintf(dbesc($hub)) . "') "; + if($address) + $sql_extra .= dir_query_build($joiner,'xchan_addr',$address); if($city) - $sql_extra .= " AND xprof_locale like '" . protect_sprintf( '%' . dbesc($city) . '%' ) . "' "; + $sql_extra .= dir_query_build($joiner,'xprof_locale',$city); if($region) - $sql_extra .= " AND xprof_region like '" . protect_sprintf( '%' . dbesc($region) . '%' ) . "' "; + $sql_extra .= dir_query_build($joiner,'xprof_region',$region); if($post) - $sql_extra .= " AND xprof_postcode like '" . protect_sprintf( '%' . dbesc($post) . '%' ) . "' "; + $sql_extra .= dir_query_build($joiner,'xprof_postcode',$post); if($country) - $sql_extra .= " AND xprof_country like '" . protect_sprintf( '%' . dbesc($country) . '%' ) . "' "; + $sql_extra .= dir_query_build($joiner,'xprof_country',$country); if($gender) - $sql_extra .= " AND xprof_gender like '" . protect_sprintf( '%' . dbesc($gender) . '%' ) . "' "; + $sql_extra .= dir_query_build($joiner,'xprof_gender',$gender); if($marital) - $sql_extra .= " AND xprof_marital like '" . protect_sprintf( '%' . dbesc($marital) . '%' ) . "' "; + $sql_extra .= dir_query_build($joiner,'xprof_marital',$marital); + if($sexual) + $sql_extra .= dir_query_build($joiner,'xprof_sexual',$sexual); if($keywords) - $sql_extra .= " AND xprof_keywords like '" . protect_sprintf( '%' . dbesc($keywords) . '%' ) . "' "; + $sql_extra .= dir_query_build($joiner,'xprof_keywords',$keywords); + + // we only support an age range currently. You must set both agege + // (greater than or equal) and agele (less than or equal) + + if($agele && $agege) { + $sql_extra .= " $joiner ( xprof_age <= " . intval($agele) . " "; + $sql_extra .= " AND xprof_age >= " . intval($agege) . ") "; + } - $perpage = (($_REQUEST['n']) ? $_REQUEST['n'] : 80); - $page = (($_REQUEST['p']) ? intval($_REQUEST['p'] - 1) : 0); - $startrec = (($page+1) * $perpage) - $perpage; + + if($hash) { + $sql_extra = " AND xchan_hash = '" . dbesc($hash) . "' "; + } + + + $perpage = (($_REQUEST['n']) ? $_REQUEST['n'] : 80); + $page = (($_REQUEST['p']) ? intval($_REQUEST['p'] - 1) : 0); + $startrec = (($page+1) * $perpage) - $perpage; + $limit = (($_REQUEST['limit']) ? intval($_REQUEST['limit']) : 0); + $return_total = ((x($_REQUEST,'return_total')) ? intval($_REQUEST['return_total']) : 0); + + // mtime is not currently working + + $mtime = ((x($_REQUEST,'mtime')) ? datetime_convert('UTC','UTC',$_REQUEST['mtime']) : ''); // ok a separate tag table won't work. // merge them into xprof $ret['success'] = true; - $r = q("SELECT COUNT(xchan_hash) AS `total` FROM xchan left join xprof on xchan_hash = xprof_hash where 1 $sql_extra"); - if($r) { - $ret['total_items'] = $r[0]['total']; + // If &limit=n, return at most n entries + // If &return_total=1, we count matching entries and return that as 'total_items' for use in pagination. + // By default we return one page (default 80 items maximum) and do not count total entries + + $logic = ((strlen($sql_extra)) ? 0 : 1); + + if($hash) + $logic = 1; + + $safesql = (($safe > 0) ? " and not ( xchan_flags & " . intval(XCHAN_FLAGS_CENSORED|XCHAN_FLAGS_SELFCENSORED) . " ) " : ''); + if($safe < 0) + $safesql = " and ( xchan_flags & " . intval(XCHAN_FLAGS_CENSORED|XCHAN_FLAGS_SELFCENSORED) . " ) "; + + if($limit) + $qlimit = " LIMIT $limit "; + else { + $qlimit = " LIMIT " . intval($startrec) . " , " . intval($perpage); + if($return_total) { + $r = q("SELECT COUNT(xchan_hash) AS `total` FROM xchan left join xprof on xchan_hash = xprof_hash where $logic $sql_extra and not ( xchan_flags & %d) and not ( xchan_flags & %d ) and not ( xchan_flags & %d ) $safesql ", + intval(XCHAN_FLAGS_HIDDEN), + intval(XCHAN_FLAGS_ORPHAN), + intval(XCHAN_FLAGS_DELETED) + ); + if($r) { + $ret['total_items'] = $r[0]['total']; + } + } } - $order = " ORDER BY `xchan_name` ASC "; - $r = q("SELECT xchan.*, xprof.* from xchan left join xprof on xchan_hash = xprof_hash where 1 $sql_extra $order LIMIT %d , %d ", - intval($startrec), - intval($perpage) - ); + if($sort_order == 'normal') + $order = " order by xchan_name asc "; + elseif($sort_order == 'reverse') + $order = " order by xchan_name desc "; + else + $order = " order by xchan_name_date desc "; + + + if($sync) { + $spkt = array('transactions' => array()); + $r = q("select * from updates where ud_date >= '%s' and ud_guid != '' order by ud_date desc", + dbesc($sync) + ); + if($r) { + foreach($r as $rr) { + $flags = array(); + if($rr['ud_flags'] & UPDATE_FLAGS_DELETED) + $flags[] = 'deleted'; + if($rr['ud_flags'] & UPDATE_FLAGS_FORCED) + $flags[] = 'forced'; + + $spkt['transactions'][] = array( + 'hash' => $rr['ud_hash'], + 'address' => $rr['ud_addr'], + 'transaction_id' => $rr['ud_guid'], + 'timestamp' => $rr['ud_date'], + 'flags' => $flags + ); + } + } + json_return_and_die($spkt); + } + else { + $r = q("SELECT xchan.*, xprof.* from xchan left join xprof on xchan_hash = xprof_hash where ( $logic $sql_extra ) and not ( xchan_flags & %d ) and not ( xchan_flags & %d ) and not ( xchan_flags & %d ) $safesql $order $qlimit ", + intval(XCHAN_FLAGS_HIDDEN), + intval(XCHAN_FLAGS_ORPHAN), + intval(XCHAN_FLAGS_DELETED) + ); + } $ret['page'] = $page + 1; $ret['records'] = count($r); @@ -91,7 +218,10 @@ function dirsearch_content(&$a) { $entry = array(); $entry['name'] = $rr['xchan_name']; + $entry['hash'] = $rr['xchan_hash']; + $entry['url'] = $rr['xchan_url']; + $entry['photo_l'] = $rr['xchan_photo_l']; $entry['photo'] = $rr['xchan_photo_m']; $entry['address'] = $rr['xchan_addr']; $entry['description'] = $rr['xprof_desc']; @@ -100,8 +230,13 @@ function dirsearch_content(&$a) { $entry['postcode'] = $rr['xprof_postcode']; $entry['country'] = $rr['xprof_country']; $entry['birthday'] = $rr['xprof_dob']; + $entry['age'] = $rr['xprof_age']; $entry['gender'] = $rr['xprof_gender']; $entry['marital'] = $rr['xprof_marital']; + $entry['sexual'] = $rr['xprof_sexual']; + $entry['about'] = $rr['xprof_about']; + $entry['homepage'] = $rr['xprof_homepage']; + $entry['hometown'] = $rr['xprof_hometown']; $entry['keywords'] = $rr['xprof_keywords']; $entries[] = $entry; @@ -109,8 +244,122 @@ function dirsearch_content(&$a) { } $ret['results'] = $entries; - + if($kw) { + $k = dir_tagadelic($kw); + if($k) { + $ret['keywords'] = array(); + foreach($k as $kv) { + $ret['keywords'][] = array('term' => $kv[0],'weight' => $kv[1], 'normalise' => $kv[2]); + } + } + } } json_return_and_die($ret); } + +function dir_query_build($joiner,$field,$s) { + $ret = ''; + if(trim($s)) + $ret .= dbesc($joiner) . " " . dbesc($field) . " like '" . protect_sprintf( '%' . dbesc($s) . '%' ) . "' "; + return $ret; +} + +function dir_parse_query($s) { + + $ret = array(); + $curr = array(); + $all = explode(' ',$s); + $quoted_string = false; + + if($all) { + foreach($all as $q) { + if($q === 'and') { + $curr['logic'] = 'and'; + continue; + } + if($q === 'or') { + $curr['logic'] = 'or'; + continue; + } + if($q === 'not') { + $curr['logic'] .= ' not'; + continue; + } + if(strpos($q,'=')) { + if(! isset($curr['logic'])) + $curr['logic'] = 'or'; + $curr['field'] = trim(substr($q,0,strpos($q,'='))); + $curr['value'] = trim(substr($q,strpos($q,'=')+1)); + if(strpos($curr['value'],'"') !== false) { + $quoted_string = true; + $curr['value'] = substr($curr['value'],strpos($curr['value'],'"')+1); + } + else { + $ret[] = $curr; + $curr = array(); + $continue; + } + } + elseif($quoted_string) { + if(strpos($q,'"') !== false) { + $curr['value'] .= ' ' . str_replace('"','',trim($q)); + $ret[] = $curr; + $curr = array(); + $quoted_string = false; + } + else + $curr['value'] .= ' ' . trim(q); + } + } + } + logger('dir_parse_query:' . print_r($ret,true),LOGGER_DATA); + return $ret; +} + + + + + + + +function list_public_sites() { + + + $r = q("select * from site where site_access != 0 and site_register !=0 order by rand()"); + $ret = array('success' => false); + + if($r) { + $ret['success'] = true; + $ret['sites'] = array(); + $insecure = array(); + + foreach($r as $rr) { + + if($rr['site_access'] == ACCESS_FREE) + $access = 'free'; + elseif($rr['site_access'] == ACCESS_PAID) + $access = 'paid'; + elseif($rr['site_access'] == ACCESS_TIERED) + $access = 'tiered'; + else + $access = 'private'; + + if($rr['site_register'] == REGISTER_OPEN) + $register = 'open'; + elseif($rr['site_register'] == REGISTER_APPROVE) + $register = 'approve'; + else + $register = 'closed'; + + if(strpos($rr['site_url'],'https://') !== false) + $ret['sites'][] = array('url' => $rr['site_url'], 'access' => $access, 'register' => $register, 'sellpage' => $rr['site_sellpage'], 'location' => $rr['site_location']); + else + $insecure[] = array('url' => $rr['site_url'], 'access' => $access, 'register' => $register, 'sellpage' => $rr['site_sellpage'], 'location' => $rr['site_location']); + } + if($insecure) { + $ret['sites'] = array_merge($ret['sites'],$insecure); + } + } + return $ret; +} diff --git a/mod/display.php b/mod/display.php index c6af8fdd2..31cce95d3 100644 --- a/mod/display.php +++ b/mod/display.php @@ -1,7 +1,9 @@ <?php -function display_content(&$a) { +function display_content(&$a, $update = 0, $load = false) { + +// logger("mod-display: update = $update load = $load"); if(intval(get_config('system','block_public')) && (! local_user()) && (! remote_user())) { notice( t('Public access denied.') . EOL); @@ -14,14 +16,17 @@ function display_content(&$a) { require_once('include/acl_selectors.php'); require_once('include/items.php'); - $o = '<div id="live-display"></div>' . "\r\n"; - - $a->page['htmlhead'] .= get_markup_template('display-head.tpl'); + $a->page['htmlhead'] .= replace_macros(get_markup_template('display-head.tpl'), array()); - if(argc() > 1) + if(argc() > 1 && argv(1) !== 'load') $item_hash = argv(1); + + if($_REQUEST['mid']) + $item_hash = $_REQUEST['mid']; + + if(! $item_hash) { $a->error = 404; notice( t('Item not found.') . EOL); @@ -30,6 +35,37 @@ function display_content(&$a) { $observer_is_owner = false; + + if(local_user() && (! $update)) { + + $channel = $a->get_channel(); + + + $channel_acl = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + + $x = array( + 'is_owner' => true, + 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''), + 'default_location' => $channel['channel_location'], + 'nickname' => $channel['channel_address'], + 'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), + + 'acl' => populate_acl($channel_acl), + 'bang' => '', + 'visitor' => true, + 'profile_uid' => local_user(), + 'return_path' => 'channel/' . $channel['channel_address'] + ); + + $o .= status_editor($a,$x); + + } + // This page can be viewed by anybody so the query could be complicated // First we'll see if there is a copy of the item which is owned by us - if we're logged in locally. // If that fails (or we aren't logged in locally), @@ -37,136 +73,173 @@ function display_content(&$a) { // and if that fails, look for a copy of the post that has no privacy restrictions. // If we find the post, but we don't find a copy that we're allowed to look at, this fact needs to be reported. -// FIXME - on the short term, we'll only do the first query. + // find a copy of the item somewhere $target_item = null; - if(local_user()) { - $r = q("select * from item where uri = '%s' and uid = %d limit 1", - dbesc($item_hash), - intval(local_user()) + $r = q("select id, uid, mid, parent_mid, item_restrict from item where mid like '%s' limit 1", + dbesc($item_hash . '%') + ); + + if($r) { + $target_item = $r[0]; + } + + if($target_item['item_restrict'] & ITEM_WEBPAGE) { + $x = q("select * from channel where channel_id = %d limit 1", + intval($target_item['uid']) ); - if($r) { - $owner = local_user(); - $observer_is_owner = true; - $target_item = $r[0]; + $y = q("select * from item_id where uid = %d and service = 'WEBPAGE' and iid = %d limit 1", + intval($target_item['uid']), + intval($target_item['id']) + ); + if($x && $y) { + goaway(z_root() . '/page/' . $x[0]['channel_address'] . '/' . $y[0]['sid']); + } + else { + notice( t('Page not found.') . EOL); + return ''; } } - // Checking for visitors is a bit harder, we'll look for this item from any of their friends that they've auth'd - // against and see if any of them are writeable. - // This will be messy. + if((! $update) && (! $load)) { + + + $o .= '<div id="live-display"></div>' . "\r\n"; + $o .= "<script> var profile_uid = " . ((intval(local_user())) ? local_user() : (-1)) + . "; var netargs = '?f='; var profile_page = " . $a->pager['page'] . "; </script>\r\n"; + + $a->page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array( + '$baseurl' => z_root(), + '$pgtype' => 'display', + '$uid' => '0', + '$gid' => '0', + '$cid' => '0', + '$cmin' => '0', + '$cmax' => '99', + '$star' => '0', + '$liked' => '0', + '$conv' => '0', + '$spam' => '0', + '$fh' => '0', + '$nouveau' => '0', + '$wall' => '0', + '$page' => (($a->pager['page'] != 1) ? $a->pager['page'] : 1), + '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), + '$search' => '', + '$order' => '', + '$file' => '', + '$cats' => '', + '$dend' => '', + '$dbegin' => '', + '$mid' => $item_hash + )); -// $nick = (($a->argc > 1) ? $a->argv[1] : ''); -// profile_load($a,$nick); -// $item_id = (($a->argc > 2) ? intval($a->argv[2]) : 0); - -// if(! $item_id) { -// $a->error = 404; -// notice( t('Item not found.') . EOL); -// return; -// } + } -// $groups = array(); + $sql_extra = public_permissions_sql(get_observer_hash()); -// $contact = null; -// $remote_contact = false; + if(($update && $load) || ($_COOKIE['jsAvailable'] != 1)) { -// $contact_id = 0; + $updateable = false; -// if(is_array($_SESSION['remote'])) { -// foreach($_SESSION['remote'] as $v) { -// if($v['uid'] == $a->profile['uid']) { -// $contact_id = $v['cid']; -// break; -// } -// } -// } + $pager_sql = sprintf(" LIMIT %d, %d ",intval($a->pager['start']), intval($a->pager['itemspage'])); -// if($contact_id) { -// $groups = init_groups_visitor($contact_id); -// $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", -// intval($contact_id), -// intval($a->profile['uid']) -// ); -// if(count($r)) { -// $contact = $r[0]; -// $remote_contact = true; -// } -// } + if($load || ($_COOKIE['jsAvailable'] != 1)) { + $r = null; -// if(! $remote_contact) { + require_once('include/identity.php'); + $sys = get_sys_channel(); -// if(local_user()) { -// $contact_id = $_SESSION['cid']; -// $contact = $a->contact; -// } -// } + if(local_user()) { + $r = q("SELECT * from item + WHERE item_restrict = 0 + and uid = %d + and mid = '%s' + limit 1", + intval(local_user()), + dbesc($target_item['parent_mid']) + ); + if($r) { + $updateable = true; -// $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1", -// intval($a->profile['uid']) -// ); -// if(count($r)) -// $a->page_contact = $r[0]; + } -// $is_owner = ((local_user()) && (local_user() == $a->profile['profile_uid']) ? true : false); + } + if($r === null) { + + $r = q("SELECT * from item + WHERE item_restrict = 0 + and mid = '%s' + AND (((( `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' + AND `item`.`deny_gid` = '' AND item_private = 0 ) + and owner_xchan in ( " . stream_perms_xchans(($observer) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " )) + OR owner_xchan = '%s') + $sql_extra ) + group by mid limit 1", + dbesc($target_item['parent_mid']), + dbesc($sys['xchan_hash']) + ); - if($a->profile['hidewall'] && (! $is_owner) && (! $remote_contact)) { - notice( t('Access to this profile has been restricted.') . EOL); - return; - } - -// if ($is_owner) -// $celeb = ((($a->user['page-flags'] == PAGE_SOAPBOX) || ($a->user['page-flags'] == PAGE_COMMUNITY)) ? true : false); - -// $x = array( -// 'is_owner' => true, -// 'allow_location' => $a->user['allow_location'], -// 'default_location' => $a->user['default-location'], -// 'nickname' => $a->user['nickname'], -// 'lockstate' => ( (is_array($a->user)) && ((strlen($a->user['allow_cid'])) || (strlen($a->user['allow_gid'])) || (strlen($a->user['deny_cid'])) || (strlen($a->user['deny_gid']))) ? 'lock' : 'unlock'), -// 'acl' => populate_acl($a->user, $celeb), -// 'bang' => '', -// 'visitor' => 'block', -// 'profile_uid' => local_user() -// ); -// $o .= status_editor($a,$x,true); - - -// FIXME -// $sql_extra = item_permissions_sql($a->profile['uid']); - - if($target_item) { - $r = q("SELECT * from item where parent = %d", - intval($target_item['parent']) - ); + } + } + else { + $r = array(); + } } - if($r) { - if((local_user()) && (local_user() == $owner)) { -// q("UPDATE `item` SET `unseen` = 0 -// WHERE `parent` = %d AND `unseen` = 1", -// intval($r[0]['parent']) -// ); + $parents_str = ids_to_querystr($r,'id'); + if($parents_str) { + + $items = q("SELECT `item`.*, `item`.`id` AS `item_id` + FROM `item` + WHERE item_restrict = 0 and parent in ( %s ) ", + dbesc($parents_str) + ); + + xchan_query($items); + $items = fetch_post_tags($items,true); + $items = conv_sort($items,'created'); } + } else { + $items = array(); + } - xchan_query($r); - $r = fetch_post_tags($r); - $o .= conversation($a,$r,'display', false); + if ($_COOKIE['jsAvailable'] == 1) { + $o .= conversation($a, $items, 'display', $update, 'client'); + } else { + $o .= conversation($a, $items, 'display', $update, 'traditional'); + } + if($updateable) { + $x = q("UPDATE item SET item_flags = ( item_flags ^ %d ) + WHERE (item_flags & %d) AND uid = %d and parent = %d ", + intval(ITEM_UNSEEN), + intval(ITEM_UNSEEN), + intval(local_user()), + intval($r[0]['parent']) + ); } - else { - $r = q("SELECT `id`,`deleted` FROM `item` WHERE `id` = '%s' OR `uri` = '%s' LIMIT 1", - dbesc($item_id), - dbesc($item_id) + + $o .= '<div id="content-complete"></div>'; + + return $o; + + +/* + elseif((! $update) && (! { + + $r = q("SELECT `id`, item_flags FROM `item` WHERE `id` = '%s' OR `mid` = '%s' LIMIT 1", + dbesc($item_hash), + dbesc($item_hash) ); - if(count($r)) { - if($r[0]['deleted']) { + if($r) { + if($r[0]['item_flags'] & ITEM_DELETED) { notice( t('Item has been removed.') . EOL ); } else { @@ -178,7 +251,7 @@ function display_content(&$a) { } } - +*/ return $o; } diff --git a/mod/editblock.php b/mod/editblock.php new file mode 100644 index 000000000..507050eb0 --- /dev/null +++ b/mod/editblock.php @@ -0,0 +1,159 @@ +<?php + + +function editblock_content(&$a) { + + + if(argc() < 2) { + notice( t('Item not found') . EOL); + return; + } + + $channel = get_channel_by_nick(argv(1)); + + if($c) { + $owner = intval($channel['channel_id']); + } + + + $o = ''; + + + // Figure out which post we're editing + $post_id = ((argc() > 2) ? intval(argv(2)) : 0); + + + if(! ($post_id && $channel)) { + notice( t('Item not found') . EOL); + return; + } + + // Now we've got a post and an owner, let's find out if we're allowed to edit it + + if(! perm_is_allowed($channel['channel_id'],get_observer_hash(),'write_pages')) { + notice( t('Permission denied.') . EOL); + return; + } + + + + // We've already figured out which item we want and whose copy we need, so we don't need anything fancy here + $itm = q("SELECT * FROM `item` WHERE `id` = %d and uid = %s LIMIT 1", + intval($post_id), + intval($channel['channel_id']) + ); + if($itm) { + $item_id = q("select * from item_id where service = 'BUILDBLOCK' and iid = %d limit 1", + $itm[0]['id'] + ); + if($item_id) + $block_title = $item_id[0]['sid']; + } + else { + notice( t('Item not found') . EOL); + return; + } + + + $plaintext = true; + + // You may or may not be a local user. + if(local_user() && feature_enabled(local_user(),'richtext')) + $plaintext = false; + + $mimeselect = ''; + $mimetype = $itm[0]['mimetype']; + + if($mimetype != 'text/bbcode') + $plaintext = true; + + if(get_config('system','page_mimetype')) + $mimeselect = '<input type="hidden" name="mimetype" value="' . $mimetype . '" />'; + else + $mimeselect = mimetype_select($itm[0]['uid'],$mimetype); + + + $o .= replace_macros(get_markup_template('edpost_head.tpl'), array( + '$title' => t('Edit Block') + )); + + + $a->page['htmlhead'] .= replace_macros(get_markup_template('jot-header.tpl'), array( + '$baseurl' => $a->get_baseurl(), + '$editselect' => (($plaintext) ? 'none' : '/(profile-jot-text|prvmail-text)/'), + '$ispublic' => ' ', // t('Visible to <strong>everybody</strong>'), + '$geotag' => '', + '$nickname' => $channel['channel_address'], + '$confirmdelete' => t('Delete block?') + )); + + + $tpl = get_markup_template("jot.tpl"); + + $jotplugins = ''; + $jotnets = ''; + + call_hooks('jot_tool', $jotplugins); + call_hooks('jot_networks', $jotnets); + + + //$tpl = replace_macros($tpl,array('$jotplugins' => $jotplugins)); + + // FIXME A return path with $_SESSION doesn't always work for observer - it may WSoD instead of loading a sensible page. + //So, send folk to the webpage list. + + $rp = 'blocks/' . $channel['channel_address']; + + $o .= replace_macros($tpl,array( + '$return_path' => $rp, + '$action' => 'item', + '$webpage' => ITEM_BUILDBLOCK, + '$share' => t('Edit'), + '$upload' => t('Upload photo'), + '$attach' => t('Attach file'), + '$weblink' => t('Insert web link'), + '$youtube' => t('Insert YouTube video'), + '$video' => t('Insert Vorbis [.ogg] video'), + '$audio' => t('Insert Vorbis [.ogg] audio'), + '$setloc' => t('Set your location'), + '$noloc' => t('Clear browser location'), + '$wait' => t('Please wait'), + '$permset' => t('Permission settings'), + '$ptyp' => $itm[0]['type'], + '$mimeselect' => $mimeselect, + '$content' => undo_post_tagging($itm[0]['body']), + '$post_id' => $post_id, + '$baseurl' => $a->get_baseurl(), + '$defloc' => $channel['channel_location'], + '$visitor' => false, + '$public' => t('Public post'), + '$jotnets' => $jotnets, + '$title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'), + '$placeholdertitle' => t('Set title'), + '$pagetitle' => $block_title, + '$category' => '', + '$placeholdercategory' => t('Categories (comma-separated list)'), + '$emtitle' => t('Example: bob@example.com, mary@example.com'), + '$lockstate' => $lockstate, + '$acl' => '', + '$bang' => '', + '$profile_uid' => (intval($channel['channel_id'])), + '$preview' => ((feature_enabled(local_user(),'preview')) ? t('Preview') : ''), + '$jotplugins' => $jotplugins, + '$sourceapp' => $itm[0]['app'], + '$defexpire' => '', + '$feature_expire' => false, + '$expires' => t('Set expiration date'), + )); + + + $ob = get_observer_hash(); + + if(($itm[0]['author_xchan'] === $ob) || ($itm[0]['owner_xchan'] === $ob)) + $o .= '<br /><br /><a class="block-delete-link" href="item/drop/' . $itm[0]['id'] . '" >' . t('Delete Block') . '</a><br />'; + + return $o; + +} + + diff --git a/mod/editlayout.php b/mod/editlayout.php new file mode 100644 index 000000000..da681cf34 --- /dev/null +++ b/mod/editlayout.php @@ -0,0 +1,152 @@ +<?php + +// What is this here for? I think it's cruft, but comment out for now in case it's here for a reason +// require_once('acl_selectors.php'); + +function editlayout_content(&$a) { + +// We first need to figure out who owns the webpage, grab it from an argument + $which = argv(1); + +// $a->get_channel() and stuff don't work here, so we've got to find the owner for ourselves. + $r = q("select channel_id from channel where channel_address = '%s'", + dbesc($which) + ); + if($r) { + $owner = intval($r[0]['channel_id']); + //logger('owner: ' . print_r($owner,true)); + } + + + + + if((local_user()) && (argc() > 2) && (argv(2) === 'view')) { + $which = $channel['channel_address']; + } + + + $o = ''; + + +// Figure out which post we're editing + $post_id = ((argc() > 2) ? intval(argv(2)) : 0); + + + if(! $post_id) { + notice( t('Item not found') . EOL); + return; + } + +// Now we've got a post and an owner, let's find out if we're allowed to edit it + + $observer = $a->get_observer(); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + $perms = get_all_perms($owner,$ob_hash); + + if(! $perms['write_pages']) { + notice( t('Permission denied.') . EOL); + return; + } + + + +// We've already figured out which item we want and whose copy we need, so we don't need anything fancy here + $itm = q("SELECT * FROM `item` WHERE `id` = %d and uid = %s LIMIT 1", + intval($post_id), + intval($owner) + ); + + $item_id = q("select * from item_id where service = 'PDL' and iid = %d limit 1", + $itm[0]['id'] + ); + if($item_id) + $layout_title = $item_id[0]['sid']; + + $plaintext = true; +// You may or may not be a local user. This won't work, + if(feature_enabled(local_user(),'richtext')) + $plaintext = false; + + $o .= replace_macros(get_markup_template('edpost_head.tpl'), array( + '$title' => t('Edit Layout') + )); + + + $a->page['htmlhead'] .= replace_macros(get_markup_template('jot-header.tpl'), array( + '$baseurl' => $a->get_baseurl(), + '$editselect' => (($plaintext) ? 'none' : '/(profile-jot-text|prvmail-text)/'), + '$ispublic' => ' ', // t('Visible to <strong>everybody</strong>'), + '$geotag' => $geotag, + '$nickname' => $a->user['nickname'], + '$confirmdelete' => t('Delete layout?') + )); + + + $tpl = get_markup_template("jot.tpl"); + + $jotplugins = ''; + $jotnets = ''; + + call_hooks('jot_tool', $jotplugins); + call_hooks('jot_networks', $jotnets); + + $channel = $a->get_channel(); + + //$tpl = replace_macros($tpl,array('$jotplugins' => $jotplugins)); + +//FIXME A return path with $_SESSION doesn't always work for observer - it may WSoD instead of loading a sensible page. So, send folk to the webpage list. + + $rp = '/layouts/' . $which; + + $o .= replace_macros($tpl,array( + '$return_path' => $rp, + '$action' => 'item', + '$webpage' => ITEM_PDL, + '$share' => t('Edit'), + '$upload' => t('Upload photo'), + '$attach' => t('Attach file'), + '$weblink' => t('Insert web link'), + '$youtube' => t('Insert YouTube video'), + '$video' => t('Insert Vorbis [.ogg] video'), + '$audio' => t('Insert Vorbis [.ogg] audio'), + '$setloc' => t('Set your location'), + '$noloc' => t('Clear browser location'), + '$wait' => t('Please wait'), + '$permset' => t('Permission settings'), + '$ptyp' => $itm[0]['type'], + '$content' => undo_post_tagging($itm[0]['body']), + '$post_id' => $post_id, + '$baseurl' => $a->get_baseurl(), + '$defloc' => $channel['channel_location'], + '$visitor' => false, + '$public' => t('Public post'), + '$jotnets' => $jotnets, + '$title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'), + '$placeholdertitle' => t('Set title'), + '$pagetitle' => $layout_title, + '$category' => '', + '$placeholdercategory' => t('Categories (comma-separated list)'), + '$emtitle' => t('Example: bob@example.com, mary@example.com'), + '$lockstate' => $lockstate, + '$acl' => '', + '$bang' => '', + '$profile_uid' => (intval($owner)), + '$preview' => ((feature_enabled(local_user(),'preview')) ? t('Preview') : ''), + '$jotplugins' => $jotplugins, + '$sourceapp' => t($a->sourcename), + '$defexpire' => '', + '$feature_expire' => false, + '$expires' => t('Set expiration date'), + )); + + $ob = get_observer_hash(); + + if(($itm[0]['author_xchan'] === $ob) || ($itm[0]['owner_xchan'] === $ob)) + $o .= '<br /><br /><a class="layout-delete-link" href="item/drop/' . $itm[0]['id'] . '" >' . t('Delete Layout') . '</a><br />'; + + return $o; + +} + + diff --git a/mod/editpost.php b/mod/editpost.php index 43c71ca8a..6556405e3 100644 --- a/mod/editpost.php +++ b/mod/editpost.php @@ -1,6 +1,9 @@ -<?php +<?php /** @file */ require_once('acl_selectors.php'); +require_once('include/crypto.php'); +require_once('include/items.php'); +require_once('include/taxonomy.php'); function editpost_content(&$a) { @@ -18,13 +21,14 @@ function editpost_content(&$a) { return; } - $itm = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", + $itm = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d and author_xchan = '%s' LIMIT 1", intval($post_id), - intval(local_user()) + intval(local_user()), + dbesc(get_observer_hash()) ); if(! count($itm)) { - notice( t('Item not found') . EOL); + notice( t('Item is not editable') . EOL); return; } @@ -32,6 +36,8 @@ function editpost_content(&$a) { if(feature_enabled(local_user(),'richtext')) $plaintext = false; + $channel = $a->get_channel(); + $o .= replace_macros(get_markup_template('edpost_head.tpl'), array( '$title' => t('Edit post') )); @@ -42,10 +48,21 @@ function editpost_content(&$a) { '$editselect' => (($plaintext) ? 'none' : '/(profile-jot-text|prvmail-text)/'), '$ispublic' => ' ', // t('Visible to <strong>everybody</strong>'), '$geotag' => $geotag, - '$nickname' => $a->user['nickname'] + '$nickname' => $channel['channel_address'], + '$expireswhen' => t('Expires YYYY-MM-DD HH:MM'), + '$confirmdelete' => t('Delete item?'), )); + + if($itm[0]['item_flags'] & ITEM_OBSCURED) { + $key = get_config('system','prvkey'); + if($itm[0]['title']) + $itm[0]['title'] = crypto_unencapsulate(json_decode_plus($itm[0]['title']),$key); + if($itm[0]['body']) + $itm[0]['body'] = crypto_unencapsulate(json_decode_plus($itm[0]['body']),$key); + } + $tpl = get_markup_template("jot.tpl"); $jotplugins = ''; @@ -59,6 +76,36 @@ function editpost_content(&$a) { //$tpl = replace_macros($tpl,array('$jotplugins' => $jotplugins)); + $category = ''; + $catsenabled = ((feature_enabled(local_user(),'categories')) ? 'categories' : ''); + + if ($catsenabled){ + $itm = fetch_post_tags($itm); + + $cats = get_terms_oftype($itm[0]['term'], TERM_CATEGORY); + + foreach ($cats as $cat) { + if (strlen($category)) + $category .= ', '; + $category .= $cat['term']; + } + + } + + if($itm[0]['attach']) { + $j = json_decode($itm[0]['attach'],true); + if($j) { + foreach($j as $jj) { + $itm[0]['body'] .= "\n" . '[attachment]' . basename($jj['href']) . ',' . $jj['revision'] . '[/attachment]' . "\n"; + } + } + } + + $cipher = get_pconfig(get_app()->profile['profile_uid'],'system','default_cipher'); + if(! $cipher) + $cipher = 'aes256'; + + $o .= replace_macros($tpl,array( '$return_path' => $_SESSION['return_url'], '$action' => 'item', @@ -78,13 +125,12 @@ function editpost_content(&$a) { '$post_id' => $post_id, '$baseurl' => $a->get_baseurl(), '$defloc' => $channel['channel_location'], - '$visitor' => 'none', - '$pvisit' => 'none', + '$visitor' => false, '$public' => t('Public post'), '$jotnets' => $jotnets, - '$title' => $itm[0]['title'], + '$title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'), '$placeholdertitle' => t('Set title'), - '$category' => file_tag_file_to_list($itm[0]['file'], 'category'), + '$category' => $category, '$placeholdercategory' => t('Categories (comma-separated list)'), '$emtitle' => t('Example: bob@example.com, mary@example.com'), '$lockstate' => $lockstate, @@ -94,6 +140,15 @@ function editpost_content(&$a) { '$preview' => ((feature_enabled(local_user(),'preview')) ? t('Preview') : ''), '$jotplugins' => $jotplugins, '$sourceapp' => t($a->sourcename), + '$catsenabled' => $catsenabled, + '$defexpire' => datetime_convert('UTC', date_default_timezone_get(),$itm[0]['expires']), + '$feature_expire' => ((feature_enabled(get_app()->profile['profile_uid'],'content_expire') && (! $webpage)) ? true : false), + '$expires' => t('Set expiration date'), + '$feature_encrypt' => ((feature_enabled(get_app()->profile['profile_uid'],'content_encrypt') && (! $webpage)) ? true : false), + '$encrypt' => t('Encrypt text'), + '$cipher' => $cipher, + '$expiryModalOK' => t('OK'), + '$expiryModalCANCEL' => t('Cancel'), )); return $o; diff --git a/mod/editwebpage.php b/mod/editwebpage.php new file mode 100644 index 000000000..b8b7a465c --- /dev/null +++ b/mod/editwebpage.php @@ -0,0 +1,192 @@ +<?php + +// Required for setting permissions. (FIXME) + +require_once('acl_selectors.php'); + +function editwebpage_content(&$a) { + + // We first need to figure out who owns the webpage, grab it from an argument + + $which = argv(1); + + // $a->get_channel() and stuff don't work here, so we've got to find the owner for ourselves. + + $r = q("select channel_id from channel where channel_address = '%s'", + dbesc($which) + ); + if($r) { + $owner = intval($r[0]['channel_id']); + //logger('owner: ' . print_r($owner,true)); + } + + $is_owner = ((local_user() && local_user() == $owner) ? true : false); + + $o = ''; + + // Figure out which post we're editing + $post_id = ((argc() > 2) ? intval(argv(2)) : 0); + + + if(! $post_id) { + notice( t('Item not found') . EOL); + return; + } + + // Now we've got a post and an owner, let's find out if we're allowed to edit it + + $observer = $a->get_observer(); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + $perms = get_all_perms($owner,$ob_hash); + + if(! $perms['write_pages']) { + notice( t('Permission denied.') . EOL); + return; + } + + + + // We've already figured out which item we want and whose copy we need, so we don't need anything fancy here + $itm = q("SELECT * FROM `item` WHERE `id` = %d and uid = %s LIMIT 1", + intval($post_id), + intval($owner) + ); + + + if($itm[0]['item_flags'] & ITEM_OBSCURED) { + $key = get_config('system','prvkey'); + if($itm[0]['title']) + $itm[0]['title'] = crypto_unencapsulate(json_decode_plus($itm[0]['title']),$key); + if($itm[0]['body']) + $itm[0]['body'] = crypto_unencapsulate(json_decode_plus($itm[0]['body']),$key); + } + + $item_id = q("select * from item_id where service = 'WEBPAGE' and iid = %d limit 1", + $itm[0]['id'] + ); + if($item_id) + $page_title = $item_id[0]['sid']; + + + + + $plaintext = true; + + if(feature_enabled($itm[0]['uid'],'richtext')) + $plaintext = false; + + $mimetype = $itm[0]['mimetype']; + + if($mimetype === 'application/x-php') { + if((! local_user()) || (local_user() != $itm[0]['uid'])) { + notice( t('Permission denied.') . EOL); + return; + } + } + + $mimeselect = ''; + + if($mimetype != 'text/bbcode') + $plaintext = true; + + if(get_config('system','page_mimetype')) + $mimeselect = '<input type="hidden" name="mimetype" value="' . $mimetype . '" />'; + else + $mimeselect = mimetype_select($itm[0]['uid'],$mimetype); + + $layout = get_config('system','page_layout'); + if($layout) + $layoutselect = '<input type="hidden" name="layout_mid" value="' . $layout . '" />'; + else + $layoutselect = layout_select($itm[0]['uid'],$itm[0]['layout_mid']); + + + $o .= replace_macros(get_markup_template('edpost_head.tpl'), array( + '$title' => t('Edit Webpage') + )); + + + $a->page['htmlhead'] .= replace_macros(get_markup_template('jot-header.tpl'), array( + '$baseurl' => $a->get_baseurl(), + '$editselect' => (($plaintext) ? 'none' : '/(profile-jot-text|prvmail-text)/'), + '$ispublic' => ' ', // t('Visible to <strong>everybody</strong>'), + '$geotag' => $geotag, + '$nickname' => $a->user['nickname'], + '$confirmdelete' => t('Delete webpage?') + )); + + + $tpl = get_markup_template("jot.tpl"); + + $jotplugins = ''; + $jotnets = ''; + + call_hooks('jot_tool', $jotplugins); + call_hooks('jot_networks', $jotnets); + + $channel = $a->get_channel(); + + //$tpl = replace_macros($tpl,array('$jotplugins' => $jotplugins)); + +//FIXME A return path with $_SESSION doesn't always work for observer - it may WSoD instead of loading a sensible page. So, send folk to the webpage list. + + $rp = 'webpages/' . $which; + + $o .= replace_macros($tpl,array( + '$return_path' => $rp, + '$webpage' => ITEM_WEBPAGE, + '$placeholdpagetitle' => t('Page link title'), + '$pagetitle' => $page_title, + + '$action' => 'item', + '$share' => t('Edit'), + '$upload' => t('Upload photo'), + '$attach' => t('Attach file'), + '$weblink' => t('Insert web link'), + '$youtube' => t('Insert YouTube video'), + '$video' => t('Insert Vorbis [.ogg] video'), + '$audio' => t('Insert Vorbis [.ogg] audio'), + '$setloc' => t('Set your location'), + '$noloc' => t('Clear browser location'), + '$wait' => t('Please wait'), + '$permset' => t('Permission settings'), + '$ptyp' => $itm[0]['type'], + '$content' => undo_post_tagging($itm[0]['body']), + '$post_id' => $post_id, + '$baseurl' => $a->get_baseurl(), + '$defloc' => $itm[0]['location'], + '$visitor' => ($is_owner) ? true : false, + '$acl' => populate_acl($itm[0],false), + '$showacl' => ($is_owner) ? true : false, + '$public' => t('Public post'), + '$jotnets' => $jotnets, + '$mimeselect' => $mimeselect, + '$layoutselect' => $layoutselect, + '$title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'), + '$placeholdertitle' => t('Set title'), + '$category' => '', + '$placeholdercategory' => t('Categories (comma-separated list)'), + '$emtitle' => t('Example: bob@example.com, mary@example.com'), + 'lockstate' => (((strlen($itm[0]['allow_cid'])) || (strlen($itm[0]['allow_gid'])) || (strlen($itm[0]['deny_cid'])) || (strlen($itm[0]['deny_gid']))) ? 'lock' : 'unlock'), + '$bang' => '', + '$profile_uid' => (intval($owner)), + '$preview' => ((feature_enabled(local_user(),'preview')) ? t('Preview') : ''), + '$jotplugins' => $jotplugins, + '$sourceapp' => t($a->sourcename), + '$defexpire' => '', + '$feature_expire' => false, + '$expires' => t('Set expiration date'), + + )); + + $ob = get_observer_hash(); + + if(($itm[0]['author_xchan'] === $ob) || ($itm[0]['owner_xchan'] === $ob)) + $o .= '<br /><br /><a class="page-delete-link" href="item/drop/' . $itm[0]['id'] . '" >' . t('Delete Webpage') . '</a><br />'; + + return $o; + +} + + diff --git a/mod/events.php b/mod/events.php index e6ee19c47..911b6c891 100755 --- a/mod/events.php +++ b/mod/events.php @@ -1,5 +1,6 @@ <?php +require_once('include/conversation.php'); require_once('include/bbcode.php'); require_once('include/datetime.php'); require_once('include/event.php'); @@ -11,7 +12,7 @@ function events_post(&$a) { return; $event_id = ((x($_POST,'event_id')) ? intval($_POST['event_id']) : 0); - $cid = ((x($_POST,'cid')) ? intval($_POST['cid']) : 0); + $xchan = ((x($_POST,'xchan')) ? dbesc($_POST['xchan']) : ''); $uid = local_user(); $startyear = intval($_POST['startyear']); $startmonth = intval($_POST['startmonth']); @@ -28,6 +29,11 @@ function events_post(&$a) { $adjust = intval($_POST['adjust']); $nofinish = intval($_POST['nofinish']); + // only allow editing your own events. + + if(($xchan) && ($xchan !== get_observer_hash())) + return; + // The default setting for the `private` field in event_store() is false, so mirror that $private_event = false; @@ -69,14 +75,7 @@ function events_post(&$a) { $share = ((intval($_POST['share'])) ? intval($_POST['share']) : 0); - $c = q("select id from contact where uid = %d and self = 1 limit 1", - intval(local_user()) - ); - if(count($c)) - $self = $c[0]['id']; - else - $self = 0; - + $channel = $a->get_channel(); if($share) { $str_group_allow = perms2str($_POST['group_allow']); @@ -85,9 +84,9 @@ function events_post(&$a) { $str_contact_deny = perms2str($_POST['contact_deny']); // Undo the pseudo-contact of self, since there are real contacts now - if( strpos($str_contact_allow, '<' . $self . '>') !== false ) + if( strpos($str_contact_allow, '<' . $channel['channel_hash'] . '>') !== false ) { - $str_contact_allow = str_replace('<' . $self . '>', '', $str_contact_allow); + $str_contact_allow = str_replace('<' . $channel['channel_hash'] . '>', '', $str_contact_allow); } // Make sure to set the `private` field as true. This is necessary to // have the posts show up correctly in Diaspora if an event is created @@ -100,23 +99,23 @@ function events_post(&$a) { else { // Note: do not set `private` field for self-only events. It will // keep even you from seeing them! - $str_contact_allow = '<' . $self . '>'; + $str_contact_allow = '<' . $channel['channel_hash'] . '>'; $str_group_allow = $str_contact_deny = $str_group_deny = ''; } $datarray = array(); - $datarray['hash'] = random_string(); $datarray['start'] = $start; $datarray['finish'] = $finish; $datarray['summary'] = $summary; - $datarray['desc'] = $desc; + $datarray['description'] = $desc; $datarray['location'] = $location; $datarray['type'] = $type; $datarray['adjust'] = $adjust; $datarray['nofinish'] = $nofinish; - $datarray['uid'] = $uid; - $datarray['cid'] = $cid; + $datarray['uid'] = local_user(); + $datarray['account'] = get_account_id(); + $datarray['event_xchan'] = $channel['channel_hash']; $datarray['allow_cid'] = $str_contact_allow; $datarray['allow_gid'] = $str_group_allow; $datarray['deny_cid'] = $str_contact_deny; @@ -126,9 +125,10 @@ function events_post(&$a) { $datarray['created'] = $created; $datarray['edited'] = $edited; - $item_id = event_store($datarray); + $event = event_store_event($datarray); + $item_id = event_store_item($datarray,$event); - if(! $cid) + if($share) proc_run('php',"include/notifier.php","event","$item_id"); } @@ -142,27 +142,42 @@ function events_content(&$a) { return; } - if(($a->argc > 2) && ($a->argv[1] === 'ignore') && intval($a->argv[2])) { + nav_set_selected('all_events'); + + if((argc() > 2) && (argv(1) === 'ignore') && intval(argv(2))) { $r = q("update event set ignore = 1 where id = %d and uid = %d limit 1", - intval($a->argv[2]), + intval(argv(2)), intval(local_user()) ); } - if(($a->argc > 2) && ($a->argv[1] === 'unignore') && intval($a->argv[2])) { + if((argc() > 2) && (argv(1) === 'unignore') && intval(argv(2))) { $r = q("update event set ignore = 0 where id = %d and uid = %d limit 1", - intval($a->argv[2]), + intval(argv(2)), intval(local_user()) ); } + $plaintext = true; + + if(feature_enabled(local_user(),'richtext')) + $plaintext = false; + + + $htpl = get_markup_template('event_head.tpl'); - $a->page['htmlhead'] .= replace_macros($htpl,array('$baseurl' => $a->get_baseurl())); + $a->page['htmlhead'] .= replace_macros($htpl,array( + '$baseurl' => $a->get_baseurl(), + '$editselect' => (($plaintext) ? 'none' : 'textareas') + )); $o =""; // tabs - $tabs = profile_tabs($a, True); + + $channel = $a->get_channel(); + + $tabs = profile_tabs($a, True, $channel['channel_address']); @@ -171,22 +186,31 @@ function events_content(&$a) { $m = 0; $ignored = ((x($_REQUEST,'ignored')) ? intval($_REQUEST['ignored']) : 0); - if($a->argc > 1) { - if($a->argc > 2 && $a->argv[1] == 'event') { + if(argc() > 1) { + if(argc() > 2 && argv(1) == 'event') { $mode = 'edit'; - $event_id = intval($a->argv[2]); + $event_id = argv(2); + } + if(argc() > 2 && argv(1) === 'add') { + $mode = 'add'; + $item_id = intval(argv(2)); } - if($a->argv[1] === 'new') { + if(argv(1) === 'new') { $mode = 'new'; - $event_id = 0; + $event_id = ''; } - if($a->argc > 2 && intval($a->argv[1]) && intval($a->argv[2])) { + if(argc() > 2 && intval(argv(1)) && intval(argv(2))) { $mode = 'view'; - $y = intval($a->argv[1]); - $m = intval($a->argv[2]); + $y = intval(argv(1)); + $m = intval(argv(2)); } } + if($mode === 'add') { + event_addtocal($item_id,local_user()); + killme(); + } + if($mode == 'view') { @@ -225,7 +249,7 @@ function events_content(&$a) { $finish = sprintf('%d-%d-%d %d:%d:%d',$y,$m,$dim,23,59,59); - if ($a->argv[1] === 'json'){ + if (argv(1) === 'json'){ if (x($_GET,'start')) $start = date("Y-m-d h:i:s", $_GET['start']); if (x($_GET,'end')) $finish = date("Y-m-d h:i:s", $_GET['end']); } @@ -236,20 +260,24 @@ function events_content(&$a) { $adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start); $adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish); - if (x($_GET,'id')){ - $r = q("SELECT `event`.*, `item`.`id` AS `itemid`,`item`.`plink`, - `item`.`author-name`, `item`.`author-avatar`, `item`.`author-link` FROM `event` LEFT JOIN `item` ON `item`.`event-id` = `event`.`id` - WHERE `event`.`uid` = %d AND `event`.`id` = %d", + $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan + from event left join item on resource_id = event_hash where resource_type = 'event' and event.uid = %d and event.id = %d limit 1", intval(local_user()), intval($_GET['id']) ); } else { - $r = q("SELECT `event`.*, `item`.`id` AS `itemid`,`item`.`plink`, - `item`.`author-name`, `item`.`author-avatar`, `item`.`author-link` FROM `event` LEFT JOIN `item` ON `item`.`event-id` = `event`.`id` - WHERE `event`.`uid` = %d and ignore = %d - AND (( `adjust` = 0 AND `finish` >= '%s' AND `start` <= '%s' ) - OR ( `adjust` = 1 AND `finish` >= '%s' AND `start` <= '%s' )) ", + + // fixed an issue with "nofinish" events not showing up in the calendar. + // There's still an issue if the finish date crosses the end of month. + // Noting this for now - it will need to be fixed here and in Friendica. + // Ultimately the finish date shouldn't be involved in the query. + + $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan + from event left join item on event_hash = resource_id + where resource_type = 'event' and event.uid = %d and event.ignore = %d + AND (( `adjust` = 0 AND ( `finish` >= '%s' or nofinish ) AND `start` <= '%s' ) + OR ( `adjust` = 1 AND ( `finish` >= '%s' or nofinish ) AND `start` <= '%s' )) ", intval(local_user()), intval($ignored), dbesc($start), @@ -257,12 +285,17 @@ function events_content(&$a) { dbesc($adjust_start), dbesc($adjust_finish) ); + } $links = array(); - if(count($r)) { + if($r) { + xchan_query($r); + $r = fetch_post_tags($r,true); + $r = sort_by_date($r); + foreach($r as $rr) { $j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], 'j') : datetime_convert('UTC','UTC',$rr['start'],'j')); if(! x($links,$j)) @@ -276,11 +309,10 @@ function events_content(&$a) { $last_date = ''; $fmt = t('l, F j'); - if(count($r)) { - $r = sort_by_date($r); + if($r) { + foreach($r as $rr) { - $j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], 'j') : datetime_convert('UTC','UTC',$rr['start'],'j')); $d = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], $fmt) : datetime_convert('UTC','UTC',$rr['start'],$fmt)); $d = day_translate($d); @@ -296,7 +328,8 @@ function events_content(&$a) { $is_first = ($d !== $last_date); $last_date = $d; - $edit = ((! $rr['cid']) ? array($a->get_baseurl().'/events/event/'.$rr['id'],t('Edit event'),'','') : null); +// FIXME + $edit = (($rr['item_flags'] & ITEM_WALL) ? array($a->get_baseurl().'/events/event/'.$rr['event_hash'],t('Edit event'),'','') : null); $title = strip_tags(html_entity_decode(bbcode($rr['summary']),ENT_QUOTES,'UTF-8')); if(! $title) { list($title, $_trash) = explode("<br",bbcode($rr['desc']),2); @@ -307,6 +340,7 @@ function events_content(&$a) { $rr['location'] = bbcode($rr['location']); $events[] = array( 'id'=>$rr['id'], + 'hash' => $rr['event_hash'], 'start'=> $start, 'end' => $end, 'allDay' => false, @@ -318,7 +352,7 @@ function events_content(&$a) { 'is_first'=>$is_first, 'item'=>$rr, 'html'=>$html, - 'plink' => array($rr['plink'],t('link to source'),'',''), + 'plink' => array($rr['plink'],t('Link to Source'),'',''), ); @@ -332,13 +366,11 @@ function events_content(&$a) { // links: array('href', 'text', 'extra css classes', 'title') if (x($_GET,'id')){ $tpl = get_markup_template("event.tpl"); - } else { -// if (get_config('experimentals','new_calendar')==1){ - $tpl = get_markup_template("events-js.tpl"); -// } else { -// $tpl = get_markup_template("events.tpl"); -// } + } + else { + $tpl = get_markup_template("events-js.tpl"); } + $o = replace_macros($tpl, array( '$baseurl' => $a->get_baseurl(), '$tabs' => $tabs, @@ -346,8 +378,7 @@ function events_content(&$a) { '$new_event'=> array($a->get_baseurl().'/events/new',t('Create New Event'),'',''), '$previus' => array($a->get_baseurl()."/events/$prevyear/$prevmonth",t('Previous'),'',''), '$next' => array($a->get_baseurl()."/events/$nextyear/$nextmonth",t('Next'),'',''), - '$calendar' => cal($y,$m,$links, ' eventcal'), - + '$calendar' => cal($y,$m,$links, ' eventcal'), '$events' => $events, @@ -360,14 +391,16 @@ function events_content(&$a) { } if($mode === 'edit' && $event_id) { - $r = q("SELECT * FROM `event` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($event_id), + $r = q("SELECT * FROM `event` WHERE event_hash = '%s' AND `uid` = %d LIMIT 1", + dbesc($event_id), intval(local_user()) ); if(count($r)) $orig_event = $r[0]; } + $channel = $a->get_channel(); + if($mode === 'edit' || $mode === 'new') { $n_checked = ((x($orig_event) && $orig_event['nofinish']) ? ' checked="checked" ' : ''); @@ -376,22 +409,18 @@ function events_content(&$a) { $d_orig = ((x($orig_event)) ? $orig_event['desc'] : ''); $l_orig = ((x($orig_event)) ? $orig_event['location'] : ''); $eid = ((x($orig_event)) ? $orig_event['id'] : 0); - $cid = ((x($orig_event)) ? $orig_event['cid'] : 0); - $uri = ((x($orig_event)) ? $orig_event['uri'] : ''); - + $event_xchan = ((x($orig_event)) ? $orig_event['event_xchan'] : $channel['channel_hash']); + $mid = ((x($orig_event)) ? $orig_event['mid'] : ''); if(! x($orig_event)) $sh_checked = ''; else - $sh_checked = (($orig_event['allow_cid'] === '<' . local_user() . '>' && (! $orig_event['allow_gid']) && (! $orig_event['deny_cid']) && (! $orig_event['deny_gid'])) ? '' : ' checked="checked" ' ); + $sh_checked = (($orig_event['allow_cid'] === '<' . $channel['channel_hash'] . '>' && (! $orig_event['allow_gid']) && (! $orig_event['deny_cid']) && (! $orig_event['deny_gid'])) ? '' : ' checked="checked" ' ); - if($cid) + if($orig_event['event_xchan']) $sh_checked .= ' disabled="disabled" '; - - $tpl = get_markup_template('event_form.tpl'); - $sdt = ((x($orig_event)) ? $orig_event['start'] : 'now'); $fdt = ((x($orig_event)) ? $orig_event['finish'] : 'now'); @@ -422,11 +451,21 @@ function events_content(&$a) { require_once('include/acl_selectors.php'); + $perm_defaults = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + + $tpl = get_markup_template('event_form.tpl'); + + $o .= replace_macros($tpl,array( '$post' => $a->get_baseurl() . '/events', '$eid' => $eid, - '$cid' => $cid, - '$uri' => $uri, + '$xchan' => $event_xchan, + '$mid' => $mid, '$title' => t('Event details'), '$desc' => sprintf( t('Format is %s %s. Starting date and Title are required.'),$dateformat,$timeformat), @@ -449,7 +488,7 @@ function events_content(&$a) { '$t_orig' => $t_orig, '$sh_text' => t('Share this event'), '$sh_checked' => $sh_checked, - '$acl' => (($cid) ? '' : populate_acl(((x($orig_event)) ? $orig_event : $a->user),false)), + '$acl' => (($orig_event['event_xchan']) ? '' : populate_acl(((x($orig_event)) ? $orig_event : $perm_defaults),false)), '$submit' => t('Submit') )); diff --git a/mod/fbrowser.php b/mod/fbrowser.php index cdcde4b17..19bd77914 100644 --- a/mod/fbrowser.php +++ b/mod/fbrowser.php @@ -5,7 +5,7 @@ * @author Fabio Comuni <fabrixxm@kirgroup.com> */ -require_once('include/Photo.php'); +require_once('include/photo/photo_driver.php'); /** * @param App $a @@ -45,7 +45,7 @@ function fbrowser_content($a){ $path[]=array($a->get_baseurl()."/fbrowser/image/".$a->argv[2]."/", $album); } - $r = q("SELECT `resource_id`, `id`, `filename`, type, min(`scale`) AS `hiq`,max(`scale`) AS `loq`, `desc` + $r = q("SELECT `resource_id`, `id`, `filename`, type, min(`scale`) AS `hiq`,max(`scale`) AS `loq`, `description` FROM `photo` WHERE `uid` = %d $sql_extra GROUP BY `resource_id` $sql_extra2", intval(local_user()) @@ -53,11 +53,20 @@ function fbrowser_content($a){ function files1($rr){ global $a; - $types = Photo::supportedTypes(); + $ph = photo_factory(''); + $types = $ph->supportedTypes(); $ext = $types[$rr['type']]; + + if($a->get_template_engine() === 'internal') { + $filename_e = template_escape($rr['filename']); + } + else { + $filename_e = $rr['filename']; + } + return array( $a->get_baseurl() . '/photo/' . $rr['resource_id'] . '-' . $rr['hiq'] . '.' .$ext, - template_escape($rr['filename']), + $filename_e, $a->get_baseurl() . '/photo/' . $rr['resource_id'] . '-' . $rr['loq'] . '.'. $ext ); } @@ -70,6 +79,7 @@ function fbrowser_content($a){ '$path' => $path, '$folders' => $albums, '$files' =>$files, + '$cancel' => t('Cancel'), )); @@ -83,7 +93,15 @@ function fbrowser_content($a){ function files2($rr){ global $a; list($m1,$m2) = explode("/",$rr['filetype']); $filetype = ( (file_exists("images/icons/$m1.png"))?$m1:"zip"); - return array( $a->get_baseurl() . '/attach/' . $rr['id'], template_escape($rr['filename']), $a->get_baseurl() . '/images/icons/16/' . $filetype . '.png'); + + if($a->get_template_engine() === 'internal') { + $filename_e = template_escape($rr['filename']); + } + else { + $filename_e = $rr['filename']; + } + + return array( $a->get_baseurl() . '/attach/' . $rr['id'], $filename_e, $a->get_baseurl() . '/images/icons/16/' . $filetype . '.png'); } $files = array_map("files2", $files); //echo "<pre>"; var_dump($files); killme(); @@ -96,6 +114,7 @@ function fbrowser_content($a){ '$path' => array( array($a->get_baseurl()."/fbrowser/image/", t("Files")) ), '$folders' => false, '$files' =>$files, + '$cancel' => t('Cancel'), )); } diff --git a/mod/feed.php b/mod/feed.php index a6adc620e..0f8296ed1 100644 --- a/mod/feed.php +++ b/mod/feed.php @@ -7,13 +7,14 @@ function feed_init(&$a) { $params = array(); - $params['begin'] = ((x($_REQUEST,'date_begin')) ? $_REQUEST['date_begin'] : '0000-00-00 00:00:00'); - $params['end'] = ((x($_REQUEST,'date_end')) ? $_REQUEST['date_end'] : ''); - $params['type'] = ((stristr(argv(0),'json')) ? 'json' : 'xml'); + $params['begin'] = ((x($_REQUEST,'date_begin')) ? $_REQUEST['date_begin'] : '0000-00-00 00:00:00'); + $params['end'] = ((x($_REQUEST,'date_end')) ? $_REQUEST['date_end'] : ''); + $params['type'] = ((stristr(argv(0),'json')) ? 'json' : 'xml'); + $params['pages'] = ((x($_REQUEST,'pages')) ? intval($_REQUEST['pages']) : 0); $channel = ''; if(argc() > 1) { - $r = q("select * from channel where channel_address = '%s' limit 1", + $r = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_address = '%s' limit 1", dbesc(argv(1)) ); if(!($r && count($r))) @@ -21,11 +22,6 @@ function feed_init(&$a) { $channel = $r[0]; - // check site and channel permissions - - if(!($channel['channel_r_stream'] & PERMS_PUBLIC)) - killme(); - if((intval(get_config('system','block_public'))) && (! get_account_id())) killme(); diff --git a/mod/filer.php b/mod/filer.php index adc6245e1..3340fc999 100644 --- a/mod/filer.php +++ b/mod/filer.php @@ -19,6 +19,20 @@ function filer_content(&$a) { if($item_id && strlen($term)){ // file item store_item_tag(local_user(),$item_id,TERM_OBJ_POST,TERM_FILE,$term,''); + + // protect the entire conversation from periodic expiration + + $r = q("select parent from item where id = %d and uid = %d limit 1", + intval($item_id), + intval(local_user()) + ); + if($r) { + $x = q("update item set item_flags = ( item_flags | %d ) where id = %d and uid = %d limit 1", + intval(ITEM_RETAINED), + intval($r[0]['parent']), + intval(local_user()) + ); + } } else { $filetags = array(); diff --git a/mod/filestorage.php b/mod/filestorage.php new file mode 100644 index 000000000..6a7eac706 --- /dev/null +++ b/mod/filestorage.php @@ -0,0 +1,144 @@ +<?php + +require_once('include/attach.php'); + +function filestorage_post(&$a) { + + $channel_id = ((x($_POST,'uid')) ? intval($_POST['uid']) : 0); + + if((! $channel_id) || (! local_user()) || ($channel_id != local_user())) { + notice( t('Permission denied.') . EOL); + return; + } + + $recurse = ((x($_POST,'recurse')) ? intval($_POST['recurse']) : 0); + $resource = ((x($_POST,'filehash')) ? notags($_POST['filehash']) : ''); + + if(! $resource) { + notice(t('Item not found.') . EOL); + return; + } + + $str_group_allow = perms2str($_REQUEST['group_allow']); + $str_contact_allow = perms2str($_REQUEST['contact_allow']); + $str_group_deny = perms2str($_REQUEST['group_deny']); + $str_contact_deny = perms2str($_REQUEST['contact_deny']); + + attach_change_permissions($channel_id,$resource,$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny,$recurse = false); + + //Build directory tree and redirect + $channel = $a->get_channel(); + $cloudPath = get_parent_cloudpath($channel_id, $channel['channel_address'], $resource) ; + goaway($cloudPath); +} + +function filestorage_content(&$a) { + + if(argc() > 1) + $which = argv(1); + else { + notice( t('Requested profile is not available.') . EOL ); + $a->error = 404; + return; + } + + $r = q("select * from channel where channel_address = '%s'", + dbesc($which) + ); + if($r) { + $channel = $r[0]; + $owner = intval($r[0]['channel_id']); + } + + $observer = $a->get_observer(); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + $perms = get_all_perms($owner,$ob_hash); + + if(! $perms['view_storage']) { + notice( t('Permission denied.') . EOL); + return; + } + + // Since we have ACL'd files in the wild, but don't have ACL here yet, we + // need to return for anyone other than the owner, despite the perms check for now. + + $is_owner = (((local_user()) && ($owner == local_user())) ? true : false); + if(! $is_owner) { + info( t('Permission Denied.') . EOL ); + return; + } + + + if(argc() > 3 && argv(3) === 'delete') { + if(! $perms['write_storage']) { + notice( t('Permission denied.') . EOL); + return; + } + + $file = intval(argv(2)); + $r = q("select hash from attach where id = %d and uid = %d limit 1", + dbesc($file), + intval($owner) + ); + if(! $r) { + notice( t('File not found.') . EOL); + goaway(z_root() . '/cloud/' . $which); + } + + attach_delete($owner,$r[0]['hash']); + + goaway(z_root() . '/cloud/' . $which); + } + + + if(argc() > 3 && argv(3) === 'edit') { + require_once('include/acl_selectors.php'); + if(! $perms['write_storage']) { + notice( t('Permission denied.') . EOL); + return; + } + $file = intval(argv(2)); + + $r = q("select id, uid, folder, filename, revision, flags, hash, allow_cid, allow_gid, deny_cid, deny_gid from attach where id = %d and uid = %d limit 1", + intval($file), + intval($owner) + ); + + $f = $r[0]; + + $channel = $a->get_channel(); + + $cloudpath = get_cloudpath($f) . (($f['flags'] & ATTACH_FLAG_DIR) ? '?f=&davguest=1' : ''); + + $aclselect_e = populate_acl($f,false); + $is_a_dir = (($f['flags'] & ATTACH_FLAG_DIR) ? true : false); + + $lockstate = (($f['allow_cid'] || $f['allow_gid'] || $f['deny_cid'] || $f['deny_gid']) ? 'lock' : 'unlock'); + + + $o = replace_macros(get_markup_template('attach_edit.tpl'), array( + '$header' => t('Edit file permissions'), + '$file' => $f, + '$cloudpath' => z_root() . '/' . $cloudpath, + '$uid' => $channel['channel_id'], + '$channelnick' => $channel['channel_address'], + '$permissions' => t('Permissions'), + '$aclselect' => $aclselect_e, + '$lockstate' => $lockstate, + '$permset' => t('Set/edit permissions'), + '$recurse' => t('Include all files and sub folders'), + '$backlink' => t('Return to file list'), + '$isadir' => $is_a_dir, + '$cpdesc' => t('Copy/paste this code to attach file to a post'), + '$cpldesc' => t('Copy/paste this URL to link file from a web page'), + '$submit' => t('Submit') + + )); + + return $o; + } + + goaway(z_root() . '/cloud/' . $which); + +} diff --git a/mod/follow.php b/mod/follow.php index fd2f8af19..663fb7536 100644 --- a/mod/follow.php +++ b/mod/follow.php @@ -6,24 +6,37 @@ require_once('include/follow.php'); function follow_init(&$a) { if(! local_user()) { - notice( t('Permission denied.') . EOL); return; } $uid = local_user(); $url = notags(trim($_REQUEST['url'])); $return_url = $_SESSION['return_url']; + $confirm = intval($_REQUEST['confirm']); - $result = new_contact($uid,$url,$a->get_channel(),true); - + $result = new_contact($uid,$url,$a->get_channel(),true,$confirm); + if($result['success'] == false) { if($result['message']) notice($result['message']); goaway($return_url); } - info( t('Channel added') . EOL); + info( t('Channel added.') . EOL); + + // If we can view their stream, pull in some posts + + if($result['abook']['abook_their_perms'] & PERMS_R_STREAM) + proc_run('php','include/onepoll.php',$result['abook']['abook_id']); + - goaway(z_root() . '/connection/' . $result['abook']['abook_id']); + goaway(z_root() . '/connedit/' . $result['abook']['abook_id'] . '?f=&follow=1'); } + +function follow_content(&$a) { + + if(! local_user()) { + return login(); + } +}
\ No newline at end of file diff --git a/mod/fsuggest.php b/mod/fsuggest.php index 9ef8f4c55..8b6f077d3 100644 --- a/mod/fsuggest.php +++ b/mod/fsuggest.php @@ -100,8 +100,9 @@ function fsuggest_content(&$a) { $o .= '<form id="fsuggest-form" action="fsuggest/' . $contact_id . '" method="post" >'; - $o .= contact_selector('suggest','suggest-select', false, - array('size' => 4, 'exclude' => $contact_id, 'networks' => 'DFRN_ONLY', 'single' => true)); +// FIXME contact_selector deprecated, removed +// $o .= contact_selector('suggest','suggest-select', false, +// array('size' => 4, 'exclude' => $contact_id, 'networks' => 'DFRN_ONLY', 'single' => true)); $o .= '<div id="fsuggest-submit-wrapper"><input id="fsuggest-submit" type="submit" name="submit" value="' . t('Submit') . '" /></div>'; diff --git a/mod/group.php b/mod/group.php index 91b9999dc..15e4ff2a3 100644 --- a/mod/group.php +++ b/mod/group.php @@ -2,12 +2,6 @@ require_once('include/group.php'); -function group_aside(&$a) { - if(local_user()) { - $a->set_widget('groups_edit',group_side('collections','group',false,(($a->argc > 1) ? intval($a->argv[1]) : 0))); - } -} - function group_post(&$a) { @@ -20,7 +14,8 @@ function group_post(&$a) { check_form_security_token_redirectOnErr('/group/new', 'group_edit'); $name = notags(trim($_POST['groupname'])); - $r = group_add(local_user(),$name); + $public = intval($_POST['public']); + $r = group_add(local_user(),$name,$public); if($r) { info( t('Collection created.') . EOL ); $r = group_byname(local_user(),$name); @@ -35,7 +30,7 @@ function group_post(&$a) { if((argc() == 2) && (intval(argv(1)))) { check_form_security_token_redirectOnErr('/group', 'group_edit'); - $r = q("SELECT * FROM `group` WHERE `id` = %d AND `uid` = %d LIMIT 1", + $r = q("SELECT * FROM `groups` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval(argv(1)), intval(local_user()) ); @@ -46,14 +41,17 @@ function group_post(&$a) { } $group = $r[0]; $groupname = notags(trim($_POST['groupname'])); - if((strlen($groupname)) && ($groupname != $group['name'])) { - $r = q("UPDATE `group` SET `name` = '%s' WHERE `uid` = %d AND `id` = %d LIMIT 1", + $public = intval($_POST['public']); + + if((strlen($groupname)) && (($groupname != $group['name']) || ($public != $group['visible']))) { + $r = q("UPDATE `groups` SET `name` = '%s', visible = %d WHERE `uid` = %d AND `id` = %d LIMIT 1", dbesc($groupname), + intval($public), intval(local_user()), intval($group['id']) ); if($r) - info( t('Collection name changed.') . EOL ); + info( t('Collection updated.') . EOL ); } goaway(z_root() . '/group/' . argv(1) . '/' . argv(2)); @@ -85,9 +83,10 @@ function group_content(&$a) { if((argc() == 2) && (argv(1) === 'new')) { return replace_macros($tpl, $context + array( - '$title' => t('Create a collection of connections.'), + '$title' => t('Create a collection of channels.'), '$gname' => array('groupname',t('Collection Name: '), '', ''), '$gid' => 'new', + '$public' => array('public',t('Members are visible to other channels'), false, ''), '$form_security_token' => get_form_security_token("group_edit"), )); @@ -98,7 +97,7 @@ function group_content(&$a) { check_form_security_token_redirectOnErr('/group', 'group_drop', 't'); if(intval(argv(2))) { - $r = q("SELECT `name` FROM `group` WHERE `id` = %d AND `uid` = %d LIMIT 1", + $r = q("SELECT `name` FROM `groups` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval(argv(2)), intval(local_user()) ); @@ -118,10 +117,10 @@ function group_content(&$a) { check_form_security_token_ForbiddenOnErr('group_member_change', 't'); - $r = q("SELECT abook_xchan from abook where abook_xchan = '%s' and abook_channel = %d and not (abook_flags & %d) and not (abook_flags & %d) and not (abook_flags & %d) limit 1", + $r = q("SELECT abook_xchan from abook where abook_xchan = '%s' and abook_channel = %d and not (xchan_flags & %d) and not (abook_flags & %d) and not (abook_flags & %d) limit 1", dbesc(argv(2)), intval(local_user()), - intval(ABOOK_FLAG_SELF), + intval(XCHAN_FLAGS_DELETED), intval(ABOOK_FLAG_BLOCKED), intval(ABOOK_FLAG_PENDING) ); @@ -133,22 +132,24 @@ function group_content(&$a) { if((argc() > 1) && (intval(argv(1)))) { require_once('include/acl_selectors.php'); - $r = q("SELECT * FROM `group` WHERE `id` = %d AND `uid` = %d AND `deleted` = 0 LIMIT 1", + $r = q("SELECT * FROM `groups` WHERE `id` = %d AND `uid` = %d AND `deleted` = 0 LIMIT 1", intval(argv(1)), intval(local_user()) ); if(! $r) { notice( t('Collection not found.') . EOL ); - goaway($a->get_baseurl() . '/connnections'); + goaway($a->get_baseurl() . '/connections'); } $group = $r[0]; + $members = group_get_members($group['id']); $preselected = array(); if(count($members)) { foreach($members as $member) - $preselected[] = $member['xchan_hash']; + if(! in_array($member['xchan_hash'],$preselected)) + $preselected[] = $member['xchan_hash']; } if($change) { @@ -182,6 +183,7 @@ function group_content(&$a) { '$gname' => array('groupname',t('Collection Name: '),$group['name'], ''), '$gid' => $group['id'], '$drop' => $drop_txt, + '$public' => array('public',t('Members are visible to other channels'), $group['visible'], ''), '$form_security_token' => get_form_security_token('group_edit'), ); @@ -201,17 +203,17 @@ function group_content(&$a) { $textmode = (($switchtotext && (count($members) > $switchtotext)) ? true : false); foreach($members as $member) { if($member['xchan_url']) { - $member['click'] = 'groupChangeMember(' . $group['id'] . ',\'' . $member['xchan_hash'] . '\',\'' . $sec_token . '\'); return true;'; + $member['click'] = 'groupChangeMember(' . $group['id'] . ',\'' . $member['xchan_hash'] . '\',\'' . $sec_token . '\'); return false;'; $groupeditor['members'][] = micropro($member,true,'mpgroup', $textmode); } else group_rmv_member(local_user(),$group['name'],$member['xchan_hash']); } - $r = q("SELECT abook.*, xchan.* FROM `abook` left join xchan on abook_xchan = xchan_hash WHERE `abook_channel` = %d AND not (abook_flags & %d) and not (abook_flags & %d) and not (abook_flags & %d) order by xchan_name asc", + $r = q("SELECT abook.*, xchan.* FROM `abook` left join xchan on abook_xchan = xchan_hash WHERE `abook_channel` = %d AND not (abook_flags & %d) and not (xchan_flags & %d) and not (abook_flags & %d) order by xchan_name asc", intval(local_user()), intval(ABOOK_FLAG_BLOCKED), - intval(ABOOK_FLAG_SELF), + intval(XCHAN_FLAGS_DELETED), intval(ABOOK_FLAG_PENDING) ); @@ -219,7 +221,7 @@ function group_content(&$a) { $textmode = (($switchtotext && (count($r) > $switchtotext)) ? true : false); foreach($r as $member) { if(! in_array($member['xchan_hash'],$preselected)) { - $member['click'] = 'groupChangeMember(' . $group['id'] . ',\'' . $member['xchan_hash'] . '\',\'' . $sec_token . '\'); return true;'; + $member['click'] = 'groupChangeMember(' . $group['id'] . ',\'' . $member['xchan_hash'] . '\',\'' . $sec_token . '\'); return false;'; $groupeditor['contacts'][] = micropro($member,true,'mpall', $textmode); } } diff --git a/mod/hcard.php b/mod/hcard.php deleted file mode 100644 index cc6d326b5..000000000 --- a/mod/hcard.php +++ /dev/null @@ -1,50 +0,0 @@ -<?php - -function hcard_init(&$a) { - - $blocked = (((get_config('system','block_public')) && (! local_user()) && (! remote_user())) ? true : false); - - if($a->argc > 1) - $which = $a->argv[1]; - else { - notice( t('No profile') . EOL ); - $a->error = 404; - return; - } - - $profile = 0; - if((local_user()) && ($a->argc > 2) && ($a->argv[2] === 'view')) { - $which = $a->user['nickname']; - $profile = $a->argv[1]; - } - - profile_load($a,$which,$profile); - - if((x($a->profile,'page-flags')) && ($a->profile['page-flags'] == PAGE_COMMUNITY)) { - $a->page['htmlhead'] .= '<meta name="friendica.community" content="true" />'; - } - if(x($a->profile,'openidserver')) - $a->page['htmlhead'] .= '<link rel="openid.server" href="' . $a->profile['openidserver'] . '" />' . "\r\n"; - if(x($a->profile,'openid')) { - $delegate = ((strstr($a->profile['openid'],'://')) ? $a->profile['openid'] : 'http://' . $a->profile['openid']); - $a->page['htmlhead'] .= '<link rel="openid.delegate" href="' . $delegate . '" />' . "\r\n"; - } - - if(! $blocked) { - $keywords = ((x($a->profile,'keywords')) ? $a->profile['keywords'] : ''); - $keywords = str_replace(array(',',' ',',,'),array(' ',',',','),$keywords); - if(strlen($keywords)) - $a->page['htmlhead'] .= '<meta name="keywords" content="' . $keywords . '" />' . "\r\n" ; - } - - $a->page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . $a->get_baseurl() . '/dfrn_poll/' . $which .'" />' . "\r\n" ; - $uri = urlencode('acct:' . $a->profile['nickname'] . '@' . $a->get_hostname() . (($a->path) ? '/' . $a->path : '')); - $a->page['htmlhead'] .= '<link rel="lrdd" type="application/xrd+xml" href="' . $a->get_baseurl() . '/xrd/?uri=' . $uri . '" />' . "\r\n"; - header('Link: <' . $a->get_baseurl() . '/xrd/?uri=' . $uri . '>; rel="lrdd"; type="application/xrd+xml"', false); - - $dfrn_pages = array('request', 'confirm', 'notify', 'poll'); - foreach($dfrn_pages as $dfrn) - $a->page['htmlhead'] .= "<link rel=\"dfrn-{$dfrn}\" href=\"".$a->get_baseurl()."/dfrn_{$dfrn}/{$which}\" />\r\n"; - -} - diff --git a/mod/help.php b/mod/help.php index af05bd47c..81ecd6ba9 100644 --- a/mod/help.php +++ b/mod/help.php @@ -1,8 +1,19 @@ <?php +/** + * You can create local site resources in doc/Site.md and either link to doc/Home.md for the standard resources + * or use our include mechanism to include it on your local page. + * + * #include doc/Home.md; + * + * The syntax is somewhat strict. + * + */ + + if(! function_exists('load_doc_file')) { function load_doc_file($s) { - global $lang; + $lang = get_app()->language; if(! isset($lang)) $lang = 'en'; $b = basename($s); @@ -21,16 +32,36 @@ function help_content(&$a) { global $lang; + $doctype = 'markdown'; + require_once('library/markdown.php'); $text = ''; - if($a->argc > 1) { + if(argc() > 1) { $text = load_doc_file('doc/' . $a->argv[1] . '.md'); - $a->page['title'] = t('Help:') . ' ' . str_replace('-',' ',notags($a->argv[1])); + $a->page['title'] = t('Help:') . ' ' . ucwords(str_replace('-',' ',notags(argv(1)))); + } + if(! $text) { + $text = load_doc_file('doc/' . $a->argv[1] . '.bb'); + if($text) + $doctype = 'bbcode'; + $a->page['title'] = t('Help:') . ' ' . ucwords(str_replace('_',' ',notags(argv(1)))); + } + if(! $text) { + $text = load_doc_file('doc/' . $a->argv[1] . '.html'); + if($text) + $doctype = 'html'; + $a->page['title'] = t('Help:') . ' ' . ucwords(str_replace('-',' ',notags(argv(1)))); + } + + if(! $text) { + $text = load_doc_file('doc/Site.md'); + $a->page['title'] = t('Help'); } if(! $text) { - $text = load_doc_file('doc/Home.md'); + $doctype = 'bbcode'; + $text = load_doc_file('doc/main.bb'); $a->page['title'] = t('Help'); } @@ -41,7 +72,29 @@ function help_content(&$a) { '$message' => t('Page not found.' ) )); } - - return Markdown($text); + + $text = preg_replace_callback("/#include (.*?)\;/ism", 'preg_callback_help_include', $text); + + if($doctype === 'html') + $content = $text; + if($doctype === 'markdown') + $content = Markdown($text); + if($doctype === 'bbcode') { + require_once('include/bbcode.php'); + $content = bbcode($text); + } + + return replace_macros(get_markup_template("help.tpl"), array( + '$content' => $content + )); } + + +function preg_callback_help_include($matches) { + + if($matches[1]) + return str_replace($matches[0],load_doc_file($matches[1]),$matches[0]); + +} + diff --git a/mod/home.php b/mod/home.php index f70ff1d02..6f7a0b5d7 100644 --- a/mod/home.php +++ b/mod/home.php @@ -1,6 +1,9 @@ <?php -if(! function_exists('home_init')) { +require_once('include/items.php'); +require_once('include/conversation.php'); + + function home_init(&$a) { $ret = array(); @@ -8,31 +11,89 @@ function home_init(&$a) { $channel = $a->get_channel(); - if(local_user() && $channel && $channel['xchan_url']) - goaway( $channel['xchan_url']); + if(local_user() && $channel && $channel['xchan_url']) { + $dest = $channel['channel_startpage']; + if(! $dest) + $dest = get_pconfig(local_user(),'system','startpage'); + if(! $dest) + $dest = z_root() . '/apps'; + + goaway($dest); + } + + if(get_account_id()) { + goaway(z_root() . '/new_channel'); + } -}} +} -if(! function_exists('home_content')) { function home_content(&$a) { $o = ''; if(x($_SESSION,'theme')) unset($_SESSION['theme']); - if(x($_SESSION,'mobile-theme')) - unset($_SESSION['mobile-theme']); + if(x($_SESSION,'mobile_theme')) + unset($_SESSION['mobile_theme']); - $o .= '<h1>' . ((x($a->config,'sitename')) ? sprintf( t("Welcome to %s") ,$a->config['sitename']) : "" ) . '</h1>'; - if(file_exists('home.html')) - $o .= file_get_contents('home.html'); + $channel_address = get_config("system", "site_channel" ); + if ($channel_address){ - $o .= login(($a->config['system']['register_policy'] == REGISTER_CLOSED) ? 0 : 1); - - call_hooks("home_content",$o); - - return $o; + // We can do better, but until we figure out auto-linkification, let's keep things simple + + $page_id = 'home'; + + $u = q("select channel_id from channel where channel_address = '%s' limit 1", + dbesc($channel_address) + ); + + if(! $u) { + notice( t('Channel not found.') . EOL); + return; + } + + $r = q("select item.* from item left join item_id on item.id = item_id.iid + where item.uid = %d and sid = '%s' and service = 'WEBPAGE' and + item_restrict = %d limit 1", + intval($u[0]['channel_id']), + dbesc($page_id), + intval(ITEM_WEBPAGE) + ); + + if(! $r) { + notice( t('Item not found.') . EOL); + return; + } + + xchan_query($r); + $r = fetch_post_tags($r,true); + $a->profile = array('profile_uid' => $u[0]['channel_id']); + $o .= prepare_page($r[0]); + return $o; + } + + if(get_config('system','projecthome')) { + $o .= file_get_contents('assets/home.html'); + $a->page['template'] = 'full'; + $a->page['title'] = t('Red Matrix - "The Network"'); + return $o; + } + + if(file_exists('home.html')) { + $o .= file_get_contents('home.html'); + } + else { + + // If there's no site channel or home contents configured, fallback to the old behaviour + $sitename = get_config('system','sitename'); + if($sitename) + $o .= '<h1>' . sprintf( t("Welcome to %s") ,$sitename) . '</h1>'; + if (! $a->config['system']['no_login_on_homepage']) + $o .= login(($a->config['system']['register_policy'] == REGISTER_CLOSED) ? 0 : 1); + } -}} + call_hooks('home_content',$o); + return $o; +} diff --git a/mod/hostxrd.php b/mod/hostxrd.php index 9b2411f26..ef86f2dd9 100644 --- a/mod/hostxrd.php +++ b/mod/hostxrd.php @@ -1,23 +1,16 @@ <?php -require_once('include/crypto.php'); - function hostxrd_init(&$a) { header('Access-Control-Allow-Origin: *'); header("Content-type: text/xml"); - $pubkey = get_config('system','site_pubkey'); - - if(! $pubkey) { - $res = new_keypair(1024); - - set_config('system','site_prvkey', $res['prvkey']); - set_config('system','site_pubkey', $res['pubkey']); - } - - $tpl = file_get_contents('view/xrd_host.tpl'); - echo str_replace(array( - '$zhost','$zroot','$domain','$zot_post','$bigkey'),array($a->get_hostname(),z_root(),z_path(),z_root() . '/post', salmon_key(get_config('system','site_pubkey'))),$tpl); - session_write_close(); - exit(); -}
\ No newline at end of file + $tpl = get_markup_template('xrd_host.tpl'); + $x = replace_macros(get_markup_template('xrd_host.tpl'), array( + '$zhost' => $a->get_hostname(), + '$zroot' => z_root() + )); + $arr = array('xrd' => $x); + call_hooks('hostxrd',$arr); + echo $arr['xrd']; + killme(); +} diff --git a/mod/import.php b/mod/import.php new file mode 100644 index 000000000..d3b237c3a --- /dev/null +++ b/mod/import.php @@ -0,0 +1,398 @@ +<?php + +// Import a channel, either by direct file upload or via +// connection to original server. + +require_once('include/Contact.php'); +require_once('include/zot.php'); +require_once('include/identity.php'); + +function import_post(&$a) { + + if(! get_account_id()) { + return; + } + + $data = null; + $seize = ((x($_REQUEST,'make_primary')) ? intval($_REQUEST['make_primary']) : 0); + + $src = $_FILES['filename']['tmp_name']; + $filename = basename($_FILES['filename']['name']); + $filesize = intval($_FILES['filename']['size']); + $filetype = $_FILES['filename']['type']; + + + if($src) { + if($filesize) { + $data = @file_get_contents($src); + } + unlink($src); + } + + if(! $src) { + $old_address = ((x($_REQUEST,'old_address')) ? $_REQUEST['old_address'] : ''); + if(! $old_address) { + logger('mod_import: nothing to import.'); + notice( t('Nothing to import.') . EOL); + return; + } + + $email = ((x($_REQUEST,'email')) ? $_REQUEST['email'] : ''); + $password = ((x($_REQUEST,'password')) ? $_REQUEST['password'] : ''); + + $channelname = substr($old_address,0,strpos($old_address,'@')); + $servername = substr($old_address,strpos($old_address,'@')+1); + + $scheme = 'https://'; + $api_path = '/api/red/channel/export/basic?f=&channel=' . $channelname; + $binary = false; + $redirects = 0; + $opts = array('http_auth' => $email . ':' . $password); + $url = $scheme . $servername . $api_path; + $ret = z_fetch_url($url, $binary, $redirects, $opts); + if(! $ret['success']) + $ret = z_fetch_url('http://' . $servername . $api_path, $binary, $redirects, $opts); + if($ret['success']) + $data = $ret['body']; + else + notice( t('Unable to download data from old server') . EOL); + + } + + if(! $data) { + logger('mod_import: empty file.'); + notice( t('Imported file is empty.') . EOL); + return; + } + + $data = json_decode($data,true); + +// logger('import: data: ' . print_r($data,true)); + +// print_r($data); + + // import channel + + $channel = $data['channel']; + + $r = q("select * from channel where (channel_guid = '%s' or channel_hash = '%s' or channel_address = '%s' ) limit 1", + dbesc($channel['channel_guid']), + dbesc($channel['channel_hash']), + dbesc($channel['channel_address']) + ); + + // We should probably also verify the hash + + if($r) { + logger('mod_import: duplicate channel. ', print_r($channel,true)); + notice( t('Cannot create a duplicate channel identifier on this system. Import failed.') . EOL); + return; + } + + unset($channel['channel_id']); + $channel['channel_account_id'] = get_account_id(); + $channel['channel_primary'] = (($seize) ? 1 : 0); + + dbesc_array($channel); + + $r = dbq("INSERT INTO channel (`" + . implode("`, `", array_keys($channel)) + . "`) VALUES ('" + . implode("', '", array_values($channel)) + . "')" ); + + if(! $r) { + logger('mod_import: channel clone failed. ', print_r($channel,true)); + notice( t('Channel clone failed. Import failed.') . EOL); + return; + } + + $r = q("select * from channel where channel_account_id = %d and channel_guid = '%s' limit 1", + intval(get_account_id()), + $channel['channel_guid'] // Already dbesc'd + ); + if(! $r) { + logger('mod_import: channel not found. ', print_r($channel,true)); + notice( t('Cloned channel not found. Import failed.') . EOL); + return; + } + // reset + $channel = $r[0]; + + set_default_login_identity(get_account_id(),$channel['channel_id'],false); + + if($data['photo']) { + require_once('include/photo/photo_driver.php'); + import_channel_photo(base64url_decode($data['photo']['data']),$data['photo']['type'],get_account_id(),$channel['channel_id']); + } + + $profiles = $data['profile']; + if($profiles) { + foreach($profiles as $profile) { + unset($profile['id']); + $profile['aid'] = get_account_id(); + $profile['uid'] = $channel['channel_id']; + + // we are going to reset all profile photos to the original + // somebody will have to fix this later and put all the applicable photos into the export + + $profile['photo'] = z_root() . '/photo/profile/l/' . $channel['channel_id']; + $profile['thumb'] = z_root() . '/photo/profile/m/' . $channel['channel_id']; + + + dbesc_array($profile); + $r = dbq("INSERT INTO profile (`" + . implode("`, `", array_keys($profile)) + . "`) VALUES ('" + . implode("', '", array_values($profile)) + . "')" ); + } + } + + + $hublocs = $data['hubloc']; + if($hublocs) { + foreach($hublocs as $hubloc) { + $arr = array( + 'guid' => $hubloc['hubloc_guid'], + 'guid_sig' => $hubloc['guid_sig'], + 'url' => $hubloc['hubloc_url'], + 'url_sig' => $hubloc['hubloc_url_sig'] + ); + if(($hubloc['hubloc_hash'] === $channel['channel_hash']) && ($hubloc['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY) && ($seize)) + $hubloc['hubloc_flags'] = ($hubloc['hubloc_flags'] ^ HUBLOC_FLAGS_PRIMARY); + + if(! zot_gethub($arr)) { + unset($hubloc['hubloc_id']); + dbesc_array($hubloc); + + $r = dbq("INSERT INTO hubloc (`" + . implode("`, `", array_keys($hubloc)) + . "`) VALUES ('" + . implode("', '", array_values($hubloc)) + . "')" ); + + } + + } + } + + // create new hubloc for the new channel at this site + + $r = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_flags, + hubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey ) + values ( '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s' )", + dbesc($channel['channel_guid']), + dbesc($channel['channel_guid_sig']), + dbesc($channel['channel_hash']), + dbesc($channel['channel_address'] . '@' . get_app()->get_hostname()), + intval(($seize) ? HUBLOC_FLAGS_PRIMARY : 0), + dbesc(z_root()), + dbesc(base64url_encode(rsa_sign(z_root(),$channel['channel_prvkey']))), + dbesc(get_app()->get_hostname()), + dbesc(z_root() . '/post'), + dbesc(get_config('system','pubkey')) + ); + + // reset the original primary hubloc if it is being seized + + if($seize) + $r = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d) where (hubloc_flags & %d) and hubloc_hash = '%s' and hubloc_url != '%s' ", + intval(HUBLOC_FLAGS_PRIMARY), + intval(HUBLOC_FLAGS_PRIMARY), + dbesc($channel['channel_hash']), + dbesc(z_root()) + ); + + // import xchans and contact photos + + if($seize) { + + // replace our existing xchan if we're seizing control + + $r = q("delete from xchan where xchan_hash = '%s' limit 1", + dbesc($channel['channel_hash']) + ); + + $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_guid_sig, xchan_pubkey, xchan_photo_l, xchan_photo_m, xchan_photo_s, xchan_addr, xchan_url, xchan_follow, xchan_connurl, xchan_name, xchan_network, xchan_photo_date, xchan_name_date ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')", + dbesc($channel['channel_hash']), + dbesc($channel['channel_guid']), + dbesc($channel['channel_guid_sig']), + dbesc($channel['channel_pubkey']), + dbesc($a->get_baseurl() . "/photo/profile/l/" . $channel['channel_id']), + dbesc($a->get_baseurl() . "/photo/profile/m/" . $channel['channel_id']), + dbesc($a->get_baseurl() . "/photo/profile/s/" . $channel['channel_id']), + dbesc($channel['channel_address'] . '@' . get_app()->get_hostname()), + dbesc(z_root() . '/channel/' . $channel['channel_address']), + dbesc(z_root() . '/follow?f=&url=%s'), + dbesc(z_root() . '/poco/' . $channel['channel_address']), + dbesc($channel['channel_name']), + dbesc('zot'), + dbesc(datetime_convert()), + dbesc(datetime_convert()) + ); + } + + $xchans = $data['xchan']; + if($xchans) { + foreach($xchans as $xchan) { + + $r = q("select xchan_hash from xchan where xchan_hash = '%s' limit 1", + dbesc($xchan['xchan_hash']) + ); + if($r) + continue; + + dbesc_array($xchan); + + $r = dbq("INSERT INTO xchan (`" + . implode("`, `", array_keys($xchan)) + . "`) VALUES ('" + . implode("', '", array_values($xchan)) + . "')" ); + + + require_once('include/photo/photo_driver.php'); + $photos = import_profile_photo($xchan['xchan_photo_l'],$xchan['xchan_hash']); + if($photos[4]) + $photodate = '0000-00-00 00:00:00'; + else + $photodate = $xchan['xchan_photo_date']; + + $r = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s', xchan_photo_date = '%s' + where xchan_hash = '%s' limit 1", + dbesc($photos[0]), + dbesc($photos[1]), + dbesc($photos[2]), + dbesc($photos[3]), + dbesc($photodate), + dbesc($xchan_hash) + ); + + } + } + +// FIXME - ensure we have an xchan if somebody is trying to pull a fast one + + + // import contacts + $abooks = $data['abook']; + if($abooks) { + foreach($abooks as $abook) { + unset($abook['abook_id']); + $abook['abook_account'] = get_account_id(); + $abook['abook_channel'] = $channel['channel_id']; + dbesc_array($abook); + $r = dbq("INSERT INTO abook (`" + . implode("`, `", array_keys($abook)) + . "`) VALUES ('" + . implode("', '", array_values($abook)) + . "')" ); + } + } + + + $configs = $data['config']; + if($configs) { + foreach($configs as $config) { + unset($config['id']); + $config['uid'] = $channel['channel_id']; + dbesc_array($config); + $r = dbq("INSERT INTO pconfig (`" + . implode("`, `", array_keys($config)) + . "`) VALUES ('" + . implode("', '", array_values($config)) + . "')" ); + } + } + + $groups = $data['group']; + if($groups) { + $saved = array(); + foreach($groups as $group) { + $saved[$group['hash']] = array('old' => $group['id']); + unset($group['id']); + $group['uid'] = $channel['channel_id']; + dbesc_array($group); + $r = dbq("INSERT INTO group (`" + . implode("`, `", array_keys($group)) + . "`) VALUES ('" + . implode("', '", array_values($group)) + . "')" ); + } + $r = q("select * from `groups` where uid = %d", + intval($channel['channel_id']) + ); + if($r) { + foreach($r as $rr) { + $saved[$rr['hash']]['new'] = $rr['id']; + } + } + } + + $group_members = $data['group_member']; + if($groups_members) { + foreach($group_members as $group_member) { + unset($group_member['id']); + $group_member['uid'] = $channel['channel_id']; + foreach($saved as $x) { + if($x['old'] == $group_member['gid']) + $group_member['gid'] = $x['new']; + } + dbesc_array($group_member); + $r = dbq("INSERT INTO group_member (`" + . implode("`, `", array_keys($group_member)) + . "`) VALUES ('" + . implode("', '", array_values($group_member)) + . "')" ); + } + } + +// FIXME - ensure we have a self entry if somebody is trying to pull a fast one + + if($seize) { + // notify old server that it is no longer primary. + + } + + // This will indirectly perform a refresh_all *and* update the directory + + proc_run('php', 'include/directory.php', $channel['channel_id']); + + // send out refresh requests + + notice( t('Import completed.') . EOL); + + change_channel($channel['channel_id']); + + goaway(z_root() . '/network' ); + + +} + + +function import_content(&$a) { + + if(! get_account_id()) { + notice( t('You must be logged in to use this feature.')); + return ''; + } + + $o = replace_macros(get_markup_template('channel_import.tpl'),array( + '$title' => t('Import Channel'), + '$desc' => t('Use this form to import an existing channel from a different server/hub. You may retrieve the channel identity from the old server/hub via the network or provide an export file. Only identity and connections/relationships will be imported. Importation of content is not yet available.'), + '$label_filename' => t('File to Upload'), + '$choice' => t('Or provide the old server/hub details'), + '$label_old_address' => t('Your old identity address (xyz@example.com)'), + '$label_old_email' => t('Your old login email address'), + '$label_old_pass' => t('Your old login password'), + '$common' => t('For either option, please choose whether to make this hub your new primary address, or whether your old location should continue this role. You will be able to post from either location, but only one can be marked as the primary location for files, photos, and media.'), + '$label_import_primary' => t('Make this hub my primary location'), + '$email' => '', + '$pass' => '', + '$submit' => t('Submit') + )); + + return $o; + +} diff --git a/mod/intro.php b/mod/intro.php deleted file mode 100644 index dd98a6c7b..000000000 --- a/mod/intro.php +++ /dev/null @@ -1,105 +0,0 @@ -<?php - -function intro_post(&$a) { - if(! local_user()) - return; - if(! intval($_REQUEST['contact_id'])) - return; - - $flags = 0; - if($_REQUEST['submit'] == t('Approve')) { - ; - } - elseif($_REQUEST['submit'] == t('Block')) { - $flags = ABOOK_FLAG_BLOCKED; - } - elseif($_REQUEST['submit'] == t('Ignore')) { - $flags = ABOOK_FLAG_IGNORED; - } - if(intval($_REQUEST['hidden'])) - $flags |= ABOOK_FLAG_HIDDEN; - - $r = q("update abook set abook_flags = %d where abook_channel = %d and abook_id = %d limit 1", - intval($flags), - intval(local_user()), - intval($_REQUEST['contact_id']) - ); - if($r) - info( t('Connection updated.') . EOL); - else - notice( t('Connection update failed.') . EOL); - -} - -function intro_aside(&$a) { - require_once('include/contact_widgets.php'); - - $a->set_widget('follow', follow_widget()); - -} - - -function intro_content(&$a) { - - if( ! local_user()) { - notice( t('Permission denied.') . EOL); - return; - } - - - $o = replace_macros(get_markup_template('intros_header.tpl'),array( - '$title' => t('Introductions and Connection Requests') - )); - - $r = q("select count(abook_id) as total from abook where abook_channel = %d and (abook_flags & %d) and not (abook_flags & %d) ", - intval(local_user()), - intval(ABOOK_FLAG_PENDING), - intval(ABOOK_FLAG_SELF) - ); - if($r) { - $a->set_pager_total($r[0]['total']); - if(! intval($r[0]['total'])) { - notice( t('No pending introductions.') . EOL); - return $o; - } - } - else { - notice( t('System error. Please try again later.') . EOL); - return $o; - } - - $r = q("select abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and (abook_flags & %d) and not (abook_flags & %d) LIMIT %d, %d", - intval(local_user()), - intval(ABOOK_FLAG_PENDING), - intval(ABOOK_FLAG_SELF), - intval($a->pager['start']), - intval($a->pager['itemspage']) - ); - - if($r) { - - $tpl = get_markup_template("intros.tpl"); - - foreach($r as $rr) { - $o .= replace_macros($tpl,array( - '$uid' => local_user(), - - '$contact_id' => $rr['abook_id'], - '$photo' => ((x($rr,'xchan_photo_l')) ? $rr['xchan_photo_l'] : "images/person-175.jpg"), - '$fullname' => $rr['xchan_name'], - '$hidden' => array('hidden', t('Hide this contact from others'), ($rr['abook_flags'] & ABOOK_FLAG_HIDDEN), ''), - '$activity' => array('activity', t('Post a new friend activity'), (intval(get_pconfig(local_user(),'system','post_newfriend')) ? '1' : 0), t('if applicable')), - '$url' => zid($rr['xchan_url']), - '$approve' => t('Approve'), - '$block' => t('Block'), - '$ignore' => t('Ignore'), - '$discard' => t('Discard') - - )); - } - } - - $o .= paginate($a); - return $o; - -}
\ No newline at end of file diff --git a/mod/invite.php b/mod/invite.php index 5eb5f6646..9e37d1e6d 100644 --- a/mod/invite.php +++ b/mod/invite.php @@ -14,6 +14,18 @@ function invite_post(&$a) { return; } + check_form_security_token_redirectOnErr('/', 'send_invite'); + + $max_invites = intval(get_config('system','max_invites')); + if(! $max_invites) + $max_invites = 50; + + $current_invites = intval(get_pconfig(local_user(),'system','sent_invites')); + if($current_invites > $max_invites) { + notice( t('Total invitation limit exceeded.') . EOL); + return; + }; + $recips = ((x($_POST,'recipients')) ? explode("\n",$_POST['recipients']) : array()); $message = ((x($_POST,'message')) ? notags(trim($_POST['message'])) : ''); @@ -30,6 +42,8 @@ function invite_post(&$a) { foreach($recips as $recip) { $recip = trim($recip); + if(! $recip) + continue; if(! valid_email($recip)) { notice( sprintf( t('%s : Not a valid email address.'), $recip) . EOL); @@ -56,14 +70,23 @@ function invite_post(&$a) { else $nmessage = $message; - $res = mail($recip, sprintf( t('Please join us on Friendica'), $a->config['sitename']), + $account = $a->get_account(); + + + $res = mail($recip, sprintf( t('Please join us on Red'), $a->config['sitename']), $nmessage, - "From: " . $a->user['email'] . "\n" + "From: " . $account['account_email'] . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit' ); if($res) { $total ++; + $current_invites ++; + set_pconfig(local_user(),'system','sent_invites',$current_invites); + if($current_invites > $max_invites) { + notice( t('Invitation limit exceeded. Please contact your site administrator.') . EOL); + return; + } } else { notice( sprintf( t('%s : Message delivery failed.'), $recip) . EOL); @@ -94,28 +117,42 @@ function invite_content(&$a) { } } - $dirloc = get_config('system','directory_submit_url'); - if(strlen($dirloc)) { - if($a->config['system']['register_policy'] == REGISTER_CLOSED) - $linktxt = sprintf( t('Visit %s for a list of public sites that you can join. Friendica members on other sites can all connect with each other, as well as with members of many other social networks.'), dirname($dirloc) . '/siteinfo'); - elseif($a->config['system']['register_policy'] != REGISTER_CLOSED) - $linktxt = sprintf( t('To accept this invitation, please visit and register at %s or any other public Friendica website.'), $a->get_baseurl()) - . "\r\n" . "\r\n" . sprintf( t('Friendica sites all inter-connect to create a huge privacy-enhanced social web that is owned and controlled by its members. They can also connect with many traditional social networks. See %s for a list of alternate Friendica sites you can join.'),dirname($dirloc) . '/siteinfo'); - } - else { - $o = t('Our apologies. This system is not currently configured to connect with other public sites or invite members.'); +// $dirloc = get_config('system','directory_submit_url'); +// if(strlen($dirloc)) { +// if($a->config['system']['register_policy'] == REGISTER_CLOSED) +// $linktxt = sprintf( t('Visit %s for a list of public sites that you can join. Friendica members on other sites can all connect with each other, as well as with members of many other social networks.'), dirname($dirloc) . '/siteinfo'); +// elseif($a->config['system']['register_policy'] != REGISTER_CLOSED) +// $linktxt = sprintf( t('To accept this invitation, please visit and register at %s or any other public Friendica website.'), $a->get_baseurl()) +// . "\r\n" . "\r\n" . sprintf( t('Friendica sites all inter-connect to create a huge privacy-enhanced social web that is owned and controlled by its members. They can also connect with many traditional social networks. See %s for a list of alternate Friendica sites you can join.'),dirname($dirloc) . '/siteinfo'); +// } +// else { +// $o = t('Our apologies. This system is not currently configured to connect with other public sites or invite members.'); +// return $o; +// } + + $ob = $a->get_observer(); + if(! $ob) return $o; - } + + $channel = $a->get_channel(); $o = replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("send_invite"), '$invite' => t('Send invitations'), '$addr_text' => t('Enter email addresses, one per line:'), '$msg_text' => t('Your message:'), - '$default_message' => t('You are cordially invited to join me and other close friends on Friendica - and help us to create a better social web.') . "\r\n" . "\r\n" + '$default_message' => t('You are cordially invited to join me and some other close friends on the Red Matrix - a revolutionary new decentralised communication and information tool.') . "\r\n" . "\r\n" . $linktxt - . "\r\n" . "\r\n" . (($invonly) ? t('You will need to supply this invitation code: $invite_code') . "\r\n" . "\r\n" : '') .t('Once you have registered, please connect with me via my profile page at:') - . "\r\n" . "\r\n" . $a->get_baseurl() . '/channel/' . $a->user['nickname'] - . "\r\n" . "\r\n" . t('For more information about the Friendica project and why we feel it is important, please visit http://friendica.com') . "\r\n" . "\r\n" , + . (($invonly) ? "\r\n" . "\r\n" . t('You will need to supply this invitation code: $invite_code') . "\r\n" . "\r\n" : '') + . t('Please visit my channel at') + . "\r\n" . "\r\n" + . z_root() . "/channel/" . $channel['channel_address'] + . "\r\n" . "\r\n" + . t('Once you have registered (on ANY Red Matrix site - they are all inter-connected), please connect with my Red Matrix channel address:') + . "\r\n" . "\r\n" . $ob['xchan_addr'] + . "\r\n" . "\r\n" . t('Click the [Register] link on the following page to join.') . "\r\n" . "\r\n" . z_root() + + . "\r\n" . "\r\n" . t('For more information about the Red Matrix Project and why it has the potential to change the internet as we know it, please visit http://getzot.com') . "\r\n" . "\r\n" , '$submit' => t('Submit') )); diff --git a/mod/item.php b/mod/item.php index 0a2c34128..5ddafb709 100644 --- a/mod/item.php +++ b/mod/item.php @@ -18,6 +18,7 @@ require_once('include/crypto.php'); require_once('include/enotify.php'); require_once('include/items.php'); +require_once('include/attach.php'); function item_post(&$a) { @@ -32,6 +33,8 @@ function item_post(&$a) { $uid = local_user(); + $channel = null; + if(x($_REQUEST,'dropitems')) { require_once('include/items.php'); $arr_drop = explode(',',$_REQUEST['dropitems']); @@ -43,7 +46,7 @@ function item_post(&$a) { call_hooks('post_local_start', $_REQUEST); - logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA); +// logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA); $api_source = ((x($_REQUEST,'api_source') && $_REQUEST['api_source']) ? true : false); @@ -57,24 +60,54 @@ function item_post(&$a) { // If you are unsure, it is prudent (and important) to leave it unset. $origin = (($api_source && array_key_exists('origin',$_REQUEST)) ? intval($_REQUEST['origin']) : 1); - $owner_hash = null; + // To represent message-ids on other networks - this will create an item_id record - $profile_uid = ((x($_REQUEST,'profile_uid')) ? intval($_REQUEST['profile_uid']) : 0); - $post_id = ((x($_REQUEST,'post_id')) ? intval($_REQUEST['post_id']) : 0); - $app = ((x($_REQUEST,'source')) ? strip_tags($_REQUEST['source']) : ''); + $namespace = (($api_source && array_key_exists('namespace',$_REQUEST)) ? strip_tags($_REQUEST['namespace']) : ''); + $remote_id = (($api_source && array_key_exists('remote_id',$_REQUEST)) ? strip_tags($_REQUEST['remote_id']) : ''); + + $owner_hash = null; + + $message_id = ((x($_REQUEST,'message_id') && $api_source) ? strip_tags($_REQUEST['message_id']) : ''); + $created = ((x($_REQUEST,'created')) ? datetime_convert('UTC','UTC',$_REQUEST['created']) : datetime_convert()); + $profile_uid = ((x($_REQUEST,'profile_uid')) ? intval($_REQUEST['profile_uid']) : 0); + $post_id = ((x($_REQUEST,'post_id')) ? intval($_REQUEST['post_id']) : 0); + $app = ((x($_REQUEST,'source')) ? strip_tags($_REQUEST['source']) : ''); + $return_path = ((x($_REQUEST,'return')) ? $_REQUEST['return'] : ''); + $preview = ((x($_REQUEST,'preview')) ? intval($_REQUEST['preview']) : 0); + $categories = ((x($_REQUEST,'category')) ? escape_tags($_REQUEST['category']) : ''); + $webpage = ((x($_REQUEST,'webpage')) ? intval($_REQUEST['webpage']) : 0); + $pagetitle = ((x($_REQUEST,'pagetitle')) ? escape_tags($_REQUEST['pagetitle']) : ''); + $layout_mid = ((x($_REQUEST,'layout_mid')) ? escape_tags($_REQUEST['layout_mid']): ''); + $plink = ((x($_REQUEST,'permalink')) ? escape_tags($_REQUEST['permalink']) : ''); + + + /* + Check service class limits + */ + if (local_user() && !(x($_REQUEST,'parent')) && !(x($_REQUEST,'post_id'))) { + $ret=item_check_service_class(local_user(),x($_REQUEST,'webpage')); + if (!$ret['success']) { + notice( t($ret['message']) . EOL) ; + if(x($_REQUEST,'return')) + goaway($a->get_baseurl() . "/" . $return_path ); + killme(); + } + } + if($pagetitle) { + require_once('library/urlify/URLify.php'); + $pagetitle = strtolower(URLify::transliterate($pagetitle)); + } - $return_path = ((x($_REQUEST,'return')) ? $_REQUEST['return'] : ''); - $preview = ((x($_REQUEST,'preview')) ? intval($_REQUEST['preview']) : 0); - $categories = ((x($_REQUEST['category'])) ? escape_tags($_REQUEST['category']) : ''); + $item_flags = $item_restrict = 0; /** * Is this a reply to something? */ $parent = ((x($_REQUEST,'parent')) ? intval($_REQUEST['parent']) : 0); - $parent_uri = ((x($_REQUEST,'parent_uri')) ? trim($_REQUEST['parent_uri']) : ''); + $parent_mid = ((x($_REQUEST,'parent_mid')) ? trim($_REQUEST['parent_mid']) : ''); $parent_item = null; $parent_contact = null; @@ -82,7 +115,7 @@ function item_post(&$a) { $parid = 0; $r = false; - if($parent || $parent_uri) { + if($parent || $parent_mid) { if(! x($_REQUEST,'type')) $_REQUEST['type'] = 'net-comment'; @@ -92,17 +125,17 @@ function item_post(&$a) { intval($parent) ); } - elseif($parent_uri && local_user()) { + elseif($parent_mid && local_user()) { // This is coming from an API source, and we are logged in - $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", - dbesc($parent_uri), + $r = q("SELECT * FROM `item` WHERE `mid` = '%s' AND `uid` = %d LIMIT 1", + dbesc($parent_mid), intval(local_user()) ); } // if this isn't the real parent of the conversation, find it if($r !== false && count($r)) { $parid = $r[0]['parent']; - $parent_uri = $r[0]['uri']; + $parent_mid = $r[0]['mid']; if($r[0]['id'] != $r[0]['parent']) { $r = q("SELECT * FROM `item` WHERE `id` = `parent` AND `parent` = %d LIMIT 1", intval($parid) @@ -116,32 +149,46 @@ function item_post(&$a) { goaway($a->get_baseurl() . "/" . $return_path ); killme(); } + + // can_comment_on_post() needs info from the following xchan_query + xchan_query($r); + $parent_item = $r[0]; $parent = $r[0]['id']; // multi-level threading - preserve the info but re-parent to our single level threading - //if(($parid) && ($parid != $parent)) - $thr_parent = $parent_uri; - if($parent_item['contact-id'] && $uid) { - $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($parent_item['contact-id']), - intval($uid) - ); - if(count($r)) - $parent_contact = $r[0]; - } + $thr_parent = $parent_mid; + + } - if($parent) logger('mod_item: item_post parent=' . $parent); $observer = $a->get_observer(); - if(! perm_is_allowed($profile_uid,$observer['xchan_hash'],(($parent) ? 'post_comments' : 'post_wall'))) { - notice( t('Permission denied.') . EOL) ; - if(x($_REQUEST,'return')) - goaway($a->get_baseurl() . "/" . $return_path ); - killme(); + + if($parent) { + logger('mod_item: item_post parent=' . $parent); + $can_comment = false; + if((array_key_exists('owner',$parent_item)) && ($parent_item['owner']['abook_flags'] & ABOOK_FLAG_SELF)) + $can_comment = perm_is_allowed($profile_uid,$observer['xchan_hash'],'post_comments'); + else + $can_comment = can_comment_on_post($observer['xchan_hash'],$parent_item); + + if(! $can_comment) { + notice( t('Permission denied.') . EOL) ; + if(x($_REQUEST,'return')) + goaway($a->get_baseurl() . "/" . $return_path ); + killme(); + } + } + else { + if(! perm_is_allowed($profile_uid,$observer['xchan_hash'],'post_wall')) { + notice( t('Permission denied.') . EOL) ; + if(x($_REQUEST,'return')) + goaway($a->get_baseurl() . "/" . $return_path ); + killme(); + } } @@ -149,6 +196,16 @@ function item_post(&$a) { $orig_post = null; + if($namespace && $remote_id) { + // It wasn't an internally generated post - see if we've got an item matching this remote service id + $i = q("select iid from item_id where service = '%s' and sid = '%s' limit 1", + dbesc($namespace), + dbesc($remote_id) + ); + if($i) + $post_id = $i[0]['iid']; + } + if($post_id) { $i = q("SELECT * FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($profile_uid), @@ -159,20 +216,22 @@ function item_post(&$a) { $orig_post = $i[0]; } - $channel = null; - if(local_user() && local_user() == $profile_uid) { - $channel = $a->get_channel(); - } - else { - $r = q("SELECT channel.*, account.* FROM channel left join account on channel.channel_account_id = account.account_id - where channel.channel_id = %d LIMIT 1", - intval($profile_uid) - ); - if(count($r)) - $channel = $r[0]; + if(! $channel) { + if(local_user() && local_user() == $profile_uid) { + $channel = $a->get_channel(); + } + else { + // posting as yourself but not necessarily to a channel you control + $r = q("select * from channel left join account on channel_account_id = account_id where channel_id = %d LIMIT 1", + intval($profile_uid) + ); + if($r) + $channel = $r[0]; + } } + if(! $channel) { logger("mod_item: no channel."); if(x($_REQUEST,'return')) @@ -194,20 +253,56 @@ function item_post(&$a) { goaway($a->get_baseurl() . "/" . $return_path ); killme(); } + + if($observer) { + logger('mod_item: post accepted from ' . $observer['xchan_name'] . ' for ' . $owner_xchan['xchan_name'], LOGGER_DEBUG); + } + + if($orig_post) { - $str_group_allow = $orig_post['allow_gid']; - $str_contact_allow = $orig_post['allow_cid']; - $str_group_deny = $orig_post['deny_gid']; - $str_contact_deny = $orig_post['deny_cid']; + $private = 0; + // webpages are allowed to change ACLs after the fact. Normal conversation items aren't. + if($webpage) { + $str_group_allow = perms2str($_REQUEST['group_allow']); + $str_contact_allow = perms2str($_REQUEST['contact_allow']); + $str_group_deny = perms2str($_REQUEST['group_deny']); + $str_contact_deny = perms2str($_REQUEST['contact_deny']); + } + else { + $str_group_allow = $orig_post['allow_gid']; + $str_contact_allow = $orig_post['allow_cid']; + $str_group_deny = $orig_post['deny_gid']; + $str_contact_deny = $orig_post['deny_cid']; + } + + if((strlen($str_group_allow)) + || strlen($str_contact_allow) + || strlen($str_group_deny) + || strlen($str_contact_deny)) { + $private = 1; + } + $location = $orig_post['location']; $coord = $orig_post['coord']; $verb = $orig_post['verb']; - $app = $orig_post['app']; - $title = escape_tags(trim($_REQUEST['title'])); - $body = escape_tags(trim($_REQUEST['body'])); - $private = $orig_post['item_private']; + $app = $orig_post['app']; + $title = $_REQUEST['title']; + $body = $_REQUEST['body']; + $item_flags = $orig_post['item_flags']; + + // force us to recalculate if we need to obscure this post + + if($item_flags & ITEM_OBSCURED) + $item_flags = ($item_flags ^ ITEM_OBSCURED); + + $item_restrict = $orig_post['item_restrict']; + $postopts = $orig_post['postopts']; + $created = $orig_post['created']; + $mid = $orig_post['mid']; + $parent_mid = $orig_post['parent_mid']; + $plink = $orig_post['plink']; } else { @@ -236,11 +331,13 @@ function item_post(&$a) { $str_contact_deny = perms2str($_REQUEST['contact_deny']); } - $title = escape_tags(trim($_REQUEST['title'])); + $location = notags(trim($_REQUEST['location'])); $coord = notags(trim($_REQUEST['coord'])); $verb = notags(trim($_REQUEST['verb'])); - $body = escape_tags(trim($_REQUEST['body'])); + $title = escape_tags(trim($_REQUEST['title'])); + $body = $_REQUEST['body']; + $postopts = ''; $private = ( ( strlen($str_group_allow) @@ -279,166 +376,236 @@ function item_post(&$a) { } } + $expires = '0000-00-00 00:00:00'; - if(feature_enabled($profile_uid,'expire')) { - // expire_quantity, e.g. '3' - // expire_units, e.g. days, weeks, months - if(x($_REQUEST,'expire_quantity') && (x($_REQUEST,'expire_units'))) { - $expire = datetime_convert(date_default_timezone_get(),'UTC', 'now + ' . $_REQUEST['expire_quantity'] . ' ' . $_REQUEST['expire_units']); + if(feature_enabled($profile_uid,'content_expire')) { + if(x($_REQUEST,'expire')) { + $expires = datetime_convert(date_default_timezone_get(),'UTC', $_REQUEST['expire']); if($expires <= datetime_convert()) $expires = '0000-00-00 00:00:00'; } } + $post_type = notags(trim($_REQUEST['type'])); - // Work around doubled linefeeds in Tinymce 3.5b2 - // First figure out if it's a status post that would've been - // created using tinymce. Otherwise leave it alone. + $mimetype = notags(trim($_REQUEST['mimetype'])); + if(! $mimetype) + $mimetype = 'text/bbcode'; - $plaintext = ((feature_enabled($profile_uid,'richtext')) ? false : true); - if((! $parent) && (! $api_source) && (! $plaintext)) { - $body = fix_mce_lf($body); + if($preview) { + $body = z_input_filter($profile_uid,$body,$mimetype); } - // get contact info for poster + // Verify ability to use html or php!!! + $execflag = false; -/* - $author = null; - $self = false; - $contact_id = 0; - - if((local_user()) && (local_user() == $profile_uid)) { - $self = true; - $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1", - intval($_SESSION['uid']) + if($mimetype === 'application/x-php') { + $z = q("select account_id, account_roles from account left join channel on channel_account_id = account_id where channel_id = %d limit 1", + intval($profile_uid) ); - } - elseif(remote_user()) { - if(is_array($_SESSION['remote'])) { - foreach($_SESSION['remote'] as $v) { - if($v['uid'] == $profile_uid) { - $contact_id = $v['cid']; - break; - } + if($z && ($z[0]['account_roles'] & ACCOUNT_ROLE_ALLOWCODE)) { + if(local_user() && (get_account_id() == $z[0]['account_id'])) { + $execflag = true; + } + else { + notice( t('Executable content type not permitted to this channel.') . EOL); + if(x($_REQUEST,'return')) + goaway($a->get_baseurl() . "/" . $return_path ); + killme(); } - } - if($contact_id) { - $r = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1", - intval($contact_id) - ); } } - if(count($r)) { - // FIXME - $author = $r[0]; - $contact_id = $author['id']; - } - // get contact info for owner - - if($profile_uid == local_user()) { - $contact_record = $author; - } - else { - $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1", - intval($profile_uid) - ); - if(count($r)) - $contact_record = $r[0]; - } + if($mimetype === 'text/bbcode') { -*/ + // BBCODE alert: the following functions assume bbcode input + // and will require alternatives for alternative content-types (text/html, text/markdown, text/plain, etc.) + // we may need virtual or template classes to implement the possible alternatives - $post_type = notags(trim($_REQUEST['type'])); + // Work around doubled linefeeds in Tinymce 3.5b2 + // First figure out if it's a status post that would've been + // created using tinymce. Otherwise leave it alone. + + $plaintext = ((feature_enabled($profile_uid,'richtext')) ? false : true); + if((! $parent) && (! $api_source) && (! $plaintext)) { + $body = fix_mce_lf($body); + } + // If we're sending a private top-level message with a single @-taggable channel as a recipient, @-tag it, if our pconfig is set. - /** - * - * When a photo was uploaded into the message using the (profile wall) ajax - * uploader, The permissions are initially set to disallow anybody but the - * owner from seeing it. This is because the permissions may not yet have been - * set for the post. If it's private, the photo permissions should be set - * appropriately. But we didn't know the final permissions on the post until - * now. So now we'll look for links of uploaded messages that are in the - * post and set them to the same permissions as the post itself. - * - */ - if(! $preview) { - fix_attached_photo_permissions($profile_uid,$owner_xchan['xchan_hash'],$body, - $str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny); + if((! $parent) && (get_pconfig($profile_uid,'system','tagifonlyrecip')) && (substr_count($str_contact_allow,'<') == 1) && ($str_group_allow == '') && ($str_contact_deny == '') && ($str_group_deny == '')) { + $x = q("select abook_id, abook_their_perms from abook where abook_xchan = '%s' and abook_channel = %d limit 1", + dbesc(str_replace(array('<','>'),array('',''),$str_contact_allow)), + intval($profile_uid) + ); + if($x && ($x[0]['abook_their_perms'] & PERMS_W_TAGWALL)) + $body .= "\n\n@group+" . $x[0]['abook_id'] . "\n"; + } - fix_attached_file_permissions($profile_uid,$owner_xchan['xchan_hash'],$body, - $str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny); + /** + * fix naked links by passing through a callback to see if this is a red site + * (already known to us) which will get a zrl, otherwise link with url, add bookmark tag to both. + * First protect any url inside certain bbcode tags so we don't double link it. + */ + + $body = preg_replace_callback('/\[code(.*?)\[\/(code)\]/ism','red_escape_codeblock',$body); + $body = preg_replace_callback('/\[url(.*?)\[\/(url)\]/ism','red_escape_codeblock',$body); + $body = preg_replace_callback('/\[zrl(.*?)\[\/(zrl)\]/ism','red_escape_codeblock',$body); + + $body = preg_replace_callback("/([^\]\='".'"'."]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\+\,]+)/ism", 'red_zrl_callback', $body); + + $body = preg_replace_callback('/\[\$b64zrl(.*?)\[\/(zrl)\]/ism','red_unescape_codeblock',$body); + $body = preg_replace_callback('/\[\$b64url(.*?)\[\/(url)\]/ism','red_unescape_codeblock',$body); + $body = preg_replace_callback('/\[\$b64code(.*?)\[\/(code)\]/ism','red_unescape_codeblock',$body); + + // fix any img tags that should be zmg + + $body = preg_replace_callback('/\[img(.*?)\](.*?)\[\/img\]/ism','red_zrlify_img_callback',$body); + + + /** + * + * When a photo was uploaded into the message using the (profile wall) ajax + * uploader, The permissions are initially set to disallow anybody but the + * owner from seeing it. This is because the permissions may not yet have been + * set for the post. If it's private, the photo permissions should be set + * appropriately. But we didn't know the final permissions on the post until + * now. So now we'll look for links of uploaded photos and attachments that are in the + * post and set them to the same permissions as the post itself. + * + * If the post was end-to-end encrypted we can't find images and attachments in the body, + * use our media_str input instead which only contains these elements - but only do this + * when encrypted content exists because the photo/attachment may have been removed from + * the post and we should keep it private. If it's encrypted we have no way of knowing + * so we'll set the permissions regardless and realise that the media may not be + * referenced in the post. + * + * What is preventing us from being able to upload photos into comments is dealing with + * the photo and attachment permissions, since we don't always know who was in the + * distribution for the top level post. + * + * We might be able to provide this functionality with a lot of fiddling: + * - if the top level post is public (make the photo public) + * - if the top level post was written by us or a wall post that belongs to us (match the top level post) + * - if the top level post has privacy mentions, add those to the permissions. + * - otherwise disallow the photo *or* make the photo public. This is the part that gets messy. + */ + + if(! $preview) { + fix_attached_photo_permissions($profile_uid,$owner_xchan['xchan_hash'],((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny); + + fix_attached_file_permissions($channel,$observer['xchan_hash'],((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny); - } + } - $body = bb_translate_video($body); + $body = bb_translate_video($body); - /** - * Fold multi-line [code] sequences - */ + /** + * Fold multi-line [code] sequences + */ - $body = preg_replace('/\[\/code\]\s*\[code\]/ism',"\n",$body); + $body = preg_replace('/\[\/code\]\s*\[code\]/ism',"\n",$body); - $body = scale_external_images($body,false); + $body = scale_external_images($body,false); - /** - * Look for any tags and linkify them - */ - $str_tags = ''; - $inform = ''; - $post_tags = array(); + /** + * Look for any tags and linkify them + */ - $tags = get_tags($body); + $str_tags = ''; + $inform = ''; + $post_tags = array(); - $tagged = array(); + $tags = get_tags($body); - $private_forum = false; + $tagged = array(); - if(count($tags)) { - foreach($tags as $tag) { + if(count($tags)) { + $first_access_tag = true; + foreach($tags as $tag) { - // If we already tagged 'Robert Johnson', don't try and tag 'Robert'. - // Robert Johnson should be first in the $tags array + // If we already tagged 'Robert Johnson', don't try and tag 'Robert'. + // Robert Johnson should be first in the $tags array - $fullnametagged = false; - for($x = 0; $x < count($tagged); $x ++) { - if(stristr($tagged[$x],$tag . ' ')) { - $fullnametagged = true; - break; + $fullnametagged = false; + for($x = 0; $x < count($tagged); $x ++) { + if(stristr($tagged[$x],$tag . ' ')) { + $fullnametagged = true; + break; + } + } + if($fullnametagged) + continue; + + $success = handle_tag($a, $body, $access_tag, $str_tags, (local_user()) ? local_user() : $profile_uid , $tag); + logger('handle_tag: ' . print_r($success,tue), LOGGER_DATA); + if(($access_tag) && (! $parent_item)) { + logger('access_tag: ' . $tag . ' ' . print_r($access_tag,true), LOGGER_DATA); + if ($first_access_tag) { + $str_contact_allow = ''; + $str_group_allow = ''; + $first_access_tag = false; + } + if(strpos($access_tag,'cid:') === 0) { + $str_contact_allow .= '<' . substr($access_tag,4) . '>'; + $access_tag = ''; + } + elseif(strpos($access_tag,'gid:') === 0) { + $str_group_allow .= '<' . substr($access_tag,4) . '>'; + $access_tag = ''; + } + } + + if($success['replaced']) { + $tagged[] = $tag; + $post_tags[] = array( + 'uid' => $profile_uid, + 'type' => $success['termtype'], + 'otype' => TERM_OBJ_POST, + 'term' => $success['term'], + 'url' => $success['url'] + ); } } - if($fullnametagged) - continue; - - $success = handle_tag($a, $body, $inform, $str_tags, (local_user()) ? local_user() : $profile_uid , $tag); - logger('handle_tag: ' . print_r($success,tue)); - - if($success['replaced']) { - $tagged[] = $tag; - $post_tags[] = array( - 'uid' => $profile_uid, - 'type' => $success['termtype'], - 'otype' => TERM_OBJ_POST, - 'term' => substr($tag,1), - 'url' => $success['url'] - ); - } - if(is_array($success['contact']) && intval($success['contact']['prv'])) { - $private_forum = true; - $private_id = $success['contact']['id']; + } + + +// logger('post_tags: ' . print_r($post_tags,true)); + + + $attachments = ''; + $match = false; + + if(preg_match_all('/(\[attachment\](.*?)\[\/attachment\])/',$body,$match)) { + $attachments = array(); + foreach($match[2] as $mtch) { + $hash = substr($mtch,0,strpos($mtch,',')); + $rev = intval(substr($mtch,strpos($mtch,','))); + $r = attach_by_hash_nodata($hash,$rev); + if($r['success']) { + $attachments[] = array( + 'href' => $a->get_baseurl() . '/attach/' . $r['data']['hash'], + 'length' => $r['data']['filesize'], + 'type' => $r['data']['filetype'], + 'title' => urlencode($r['data']['filename']), + 'revision' => $r['data']['revision'] + ); + } + $body = str_replace($match[1],'',$body); } } } +// BBCODE end alert + if(strlen($categories)) { $cats = explode(',',$categories); foreach($cats as $cat) { @@ -447,40 +614,12 @@ function item_post(&$a) { 'type' => TERM_CATEGORY, 'otype' => TERM_OBJ_POST, 'term' => trim($cat), - 'url' => '' + 'url' => $owner_xchan['xchan_url'] . '?f=&cat=' . urlencode(trim($cat)) ); } } -// logger('post_tags: ' . print_r($post_tags,true)); - - if(($private_forum) && (! $parent) && (! $private)) { - // we tagged a private forum in a top level post and the message was public. - // Restrict it. - $private = 1; - $str_contact_allow = '<' . $private_id . '>'; - } - - $attachments = ''; - $match = false; - - if(preg_match_all('/(\[attachment\](.*?)\[\/attachment\])/',$body,$match)) { - foreach($match[2] as $mtch) { - $r = q("SELECT `hash`,`filename`,`filesize`,`filetype` FROM `attach` WHERE `uid` = %d AND `hash` = '%s' LIMIT 1", - intval($profile_uid), - dbesc($mtch) - ); - if(count($r)) { - if(strlen($attachments)) - $attachments .= ','; - $attachments .= '[attach]href="' . $a->get_baseurl() . '/attach/' . $r[0]['hash'] . '" length="' . $r[0]['filesize'] . '" type="' . $r[0]['filetype'] . '" title="' . (($r[0]['filename']) ? $r[0]['filename'] : '') . '"[/attach]'; - } - $body = str_replace($match[1],'',$body); - } - } - - $item_flags = ITEM_UNSEEN; - $item_restrict = ITEM_VISIBLE; + $item_flags |= ITEM_UNSEEN; if($post_type === 'wall' || $post_type === 'wall-comment') $item_flags = $item_flags | ITEM_WALL; @@ -491,7 +630,8 @@ function item_post(&$a) { if($moderated) $item_restrict = $item_restrict | ITEM_MODERATED; - + if($webpage) + $item_restrict = $item_restrict | $webpage; if(! strlen($verb)) @@ -499,54 +639,65 @@ function item_post(&$a) { $notify_type = (($parent) ? 'comment-new' : 'wall-new' ); - $uri = item_message_id(); - $parent_uri = $uri; + if(! $mid) { + $mid = (($message_id) ? $message_id : item_message_id()); + } + if(! $parent_mid) { + $parent_mid = $mid; + } + if($parent_item) - $parent_uri = $parent_item['uri']; + $parent_mid = $parent_item['mid']; // Fallback so that we alway have a thr_parent if(!$thr_parent) - $thr_parent = $uri; + $thr_parent = $mid; $datarray = array(); if(! $parent) { - $datarray['parent_uri'] = $uri; $item_flags = $item_flags | ITEM_THREAD_TOP; } - - $datarray['aid'] = $channel['channel_account_id']; - $datarray['uid'] = $profile_uid; - - $datarray['owner_xchan'] = (($owner_hash) ? $owner_hash : $owner_xchan['xchan_hash']); - $datarray['author_xchan'] = $observer['xchan_hash']; - $datarray['created'] = datetime_convert(); - $datarray['edited'] = datetime_convert(); - $datarray['expires'] = $expires; - $datarray['commented'] = datetime_convert(); - $datarray['received'] = datetime_convert(); - $datarray['changed'] = datetime_convert(); - $datarray['uri'] = $uri; - $datarray['parent_uri'] = $parent_uri; - $datarray['title'] = $title; - $datarray['body'] = $body; - $datarray['app'] = $app; - $datarray['location'] = $location; - $datarray['coord'] = $coord; - $datarray['inform'] = $inform; - $datarray['verb'] = $verb; - $datarray['allow_cid'] = $str_contact_allow; - $datarray['allow_gid'] = $str_group_allow; - $datarray['deny_cid'] = $str_contact_deny; - $datarray['deny_gid'] = $str_group_deny; - $datarray['item_private'] = $private; - $datarray['attach'] = $attachments; - $datarray['thr_parent'] = $thr_parent; - $datarray['postopts'] = ''; - $datarray['item_restrict'] = $item_restrict; - $datarray['item_flags'] = $item_flags; + if ((! $plink) && ($item_flags & ITEM_THREAD_TOP)) { + $plink = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $mid; + } + + $datarray['aid'] = $channel['channel_account_id']; + $datarray['uid'] = $profile_uid; + + $datarray['owner_xchan'] = (($owner_hash) ? $owner_hash : $owner_xchan['xchan_hash']); + $datarray['author_xchan'] = $observer['xchan_hash']; + $datarray['created'] = $created; + $datarray['edited'] = (($orig_post) ? datetime_convert() : $created); + $datarray['expires'] = $expires; + $datarray['commented'] = (($orig_post) ? datetime_convert() : $created); + $datarray['received'] = (($orig_post) ? datetime_convert() : $created); + $datarray['changed'] = (($orig_post) ? datetime_convert() : $created); + $datarray['mid'] = $mid; + $datarray['parent_mid'] = $parent_mid; + $datarray['mimetype'] = $mimetype; + $datarray['title'] = $title; + $datarray['body'] = $body; + $datarray['app'] = $app; + $datarray['location'] = $location; + $datarray['coord'] = $coord; + $datarray['verb'] = $verb; + $datarray['allow_cid'] = $str_contact_allow; + $datarray['allow_gid'] = $str_group_allow; + $datarray['deny_cid'] = $str_contact_deny; + $datarray['deny_gid'] = $str_group_deny; + $datarray['item_private'] = $private; + $datarray['attach'] = $attachments; + $datarray['thr_parent'] = $thr_parent; + $datarray['postopts'] = $postopts; + $datarray['item_restrict'] = $item_restrict; + $datarray['item_flags'] = $item_flags; + $datarray['layout_mid'] = $layout_mid; + $datarray['comment_policy'] = map_scope($channel['channel_w_comment']); + $datarray['term'] = $post_tags; + $datarray['plink'] = $plink; // preview mode - prepare the body for display and send it via json @@ -555,11 +706,14 @@ function item_post(&$a) { $datarray['owner'] = $owner_xchan; $datarray['author'] = $observer; + $datarray['attach'] = json_encode($datarray['attach']); $o = conversation($a,array($datarray),'search',false,'preview'); logger('preview: ' . $o, LOGGER_DEBUG); echo json_encode(array('preview' => $o)); killme(); } + if($orig_post) + $datarray['edit'] = true; call_hooks('post_local',$datarray); @@ -578,27 +732,35 @@ function item_post(&$a) { } - if($orig_post) { - $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `attach` = '%s', `edited` = '%s' WHERE `id` = %d AND `uid` = %d LIMIT 1", - dbesc($datarray['title']), - dbesc($datarray['body']), - dbesc($datarray['attach']), - dbesc(datetime_convert()), - intval($post_id), - intval($profile_uid) - ); + if(mb_strlen($datarray['title']) > 255) + $datarray['title'] = mb_substr($datarray['title'],0,255); - // remove taxonomy items for this post - we'll recreate them + if(array_key_exists('item_private',$datarray) && $datarray['item_private']) { - q("delete from term where otype = %d and oid = %d and type in (%d, %d, %d, %d) ", - intval(TERM_OBJ_POST), - intval($post_id), - intval(TERM_UNKNOWN), - intval(TERM_HASHTAG), - intval(TERM_MENTION), - intval(TERM_CATEGORY) - ); + $datarray['body'] = z_input_filter($datarray['uid'],$datarray['body'],$datarray['mimetype']); + + if(local_user()) { + if($channel['channel_hash'] === $datarray['author_xchan']) { + $datarray['sig'] = base64url_encode(rsa_sign($datarray['body'],$channel['channel_prvkey'])); + $datarray['item_flags'] = $datarray['item_flags'] | ITEM_VERIFIED; + } + } + + logger('Encrypting local storage'); + $key = get_config('system','pubkey'); + $datarray['item_flags'] = $datarray['item_flags'] | ITEM_OBSCURED; + if($datarray['title']) + $datarray['title'] = json_encode(aes_encapsulate($datarray['title'],$key)); + if($datarray['body']) + $datarray['body'] = json_encode(aes_encapsulate($datarray['body'],$key)); + } + + if($orig_post) { + $datarray['id'] = $post_id; + + item_store_update($datarray,$execflag); + update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remote_id,$mid); proc_run('php', "include/notifier.php", 'edit_post', $post_id); if((x($_REQUEST,'return')) && strlen($return_path)) { @@ -611,108 +773,49 @@ function item_post(&$a) { $post_id = 0; - $post_id = item_store($datarray); + $post = item_store($datarray,$execflag); + + $post_id = $post['item_id']; if($post_id) { logger('mod_item: saved item ' . $post_id); - if(count($post_tags)) { - foreach($post_tags as $tag) { - if(strlen(trim($tag['term']))) { - q("insert into term (uid,oid,otype,type,term,url) values (%d,%d,%d,%d,'%s','%s')", - intval($tag['uid']), - intval($post_id), - intval($tag['otype']), - intval($tag['type']), - dbesc(trim($tag['term'])), - dbesc(trim($tag['url'])) - ); - } - } - } - if($parent) { - - $r = q("UPDATE `item` SET `changed` = '%s' WHERE `parent` = %d ", - dbesc(datetime_convert()), - intval($parent) - ); - - // Inherit ACL's from the parent item. - - $r = q("UPDATE `item` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s', `item_private` = %d - WHERE `id` = %d LIMIT 1", - dbesc($parent_item['allow_cid']), - dbesc($parent_item['allow_gid']), - dbesc($parent_item['deny_cid']), - dbesc($parent_item['deny_gid']), - intval($parent_item['private']), - intval($post_id) - ); -//fixme - if($contact_record != $author) { + if($datarray['owner_xchan'] != $datarray['author_xchan']) { notification(array( 'type' => NOTIFY_COMMENT, - 'notify_flags' => $channel['channel_notifyflags'], - 'language' => $channel['account_language'], - 'to_name' => $channel['channel_name'], - 'to_email' => $channel['account_email'], - 'uid' => $channel['channel_id'], + 'from_xchan' => $datarray['author_xchan'], + 'to_xchan' => $datarray['owner_xchan'], 'item' => $datarray, - 'link' => $a->get_baseurl() . '/display/' . $user['nickname'] . '/' . $post_id, - 'source_name' => $datarray['author-name'], - 'source_link' => $datarray['author-link'], - 'source_photo' => $datarray['author-avatar'], + 'link' => $a->get_baseurl() . '/display/' . $datarray['mid'], 'verb' => ACTIVITY_POST, 'otype' => 'item', 'parent' => $parent, - 'parent_uri' => $parent_item['uri'] + 'parent_mid' => $parent_item['mid'] )); } - } else { $parent = $post_id; -//fixme - if($contact_record != $author) { + + if($datarray['owner_xchan'] != $datarray['author_xchan']) { notification(array( 'type' => NOTIFY_WALL, - 'notify_flags' => $channel['channel_notifyflags'], - 'language' => $channel['account_language'], - 'to_name' => $channel['channel_name'], - 'to_email' => $channel['account_email'], - 'uid' => $channel['channel_id'], + 'from_xchan' => $datarray['author_xchan'], + 'to_xchan' => $datarray['owner_xchan'], 'item' => $datarray, - 'link' => $a->get_baseurl() . '/display/' . $user['nickname'] . '/' . $post_id, - 'source_name' => $datarray['author-name'], - 'source_link' => $datarray['author-link'], - 'source_photo' => $datarray['author-avatar'], + 'link' => $a->get_baseurl() . '/display/' . $datarray['mid'], 'verb' => ACTIVITY_POST, 'otype' => 'item' )); } } - // fallback so that parent always gets set to non-zero. - - if(! $parent) - $parent = $post_id; - - $r = q("UPDATE `item` SET `parent` = %d, `parent_uri` = '%s', `changed` = '%s' - WHERE `id` = %d LIMIT 1", - intval($parent), - dbesc(($parent == $post_id) ? $uri : $parent_item['uri']), - dbesc(datetime_convert()), - intval($post_id) - ); - // photo comments turn the corresponding item visible to the profile wall // This way we don't see every picture in your new photo album posted to your wall at once. // They will show up as people comment on them. -// fixme set item visible as well - if($parent_item['item_restrict'] & ITEM_HIDDEN) { $r = q("UPDATE `item` SET `item_restrict` = %d WHERE `id` = %d LIMIT 1", intval($parent_item['item_restrict'] - ITEM_HIDDEN), @@ -727,16 +830,11 @@ function item_post(&$a) { // NOTREACHED } - // update the commented timestamp on the parent - q("UPDATE `item` set `commented` = '%s', `changed` = '%s' WHERE `id` = %d LIMIT 1", - dbesc(datetime_convert()), - dbesc(datetime_convert()), - intval($parent) - ); + update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remote_id,$mid); $datarray['id'] = $post_id; - $datarray['plink'] = $a->get_baseurl() . '/display/' . $channel['channel_address'] . '/' . $post_id; + $datarray['llink'] = $a->get_baseurl() . '/display/' . $channel['channel_address'] . '/' . $post_id; call_hooks('post_local_end', $datarray); @@ -747,7 +845,7 @@ function item_post(&$a) { // figure out how to return, depending on from whence we came if($api_source) - return; + return $post; if($return_path) { goaway($a->get_baseurl() . "/" . $return_path); @@ -775,9 +873,40 @@ function item_content(&$a) { require_once('include/security.php'); - if(($a->argc == 3) && ($a->argv[1] === 'drop') && intval($a->argv[2])) { + if((argc() == 3) && (argv(1) === 'drop') && intval(argv(2))) { + require_once('include/items.php'); - drop_item($a->argv[2]); + $i = q("select id, uid, author_xchan, owner_xchan, source_xchan, item_restrict from item where id = %d limit 1", + intval(argv(2)) + ); + + if($i) { + $can_delete = false; + $local_delete = false; + if(local_user() && local_user() == $i[0]['uid']) + $local_delete = true; + + $ob_hash = get_observer_hash(); + if($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) + $can_delete = true; + + if(! ($can_delete || $local_delete)) { + notice( t('Permission denied.') . EOL); + return; + } + + // if this is a different page type or it's just a local delete + // but not by the item author or owner, do a simple deletion + + if($i[0]['item_restrict'] || ($local_delete && (! $can_delete))) { + drop_item($i[0]['id']); + } + else { + // complex deletion that needs to propagate and be performed in phases + drop_item($i[0]['id'],true,DROPITEM_PHASE1); + tag_deliver($i[0]['uid'],$i[0]['id']); + } + } } } @@ -786,36 +915,64 @@ function item_content(&$a) { * the appropiate link. * * @param unknown_type $body the text to replace the tag in - * @param unknown_type $inform a comma-seperated string containing everybody to inform + * @param unknown_type $access_tag - used to return tag ACL exclusions e.g. @!foo * @param unknown_type $str_tags string to add the tag to * @param unknown_type $profile_uid * @param unknown_type $tag the tag to replace * * @return boolean true if replaced, false if not replaced */ -function handle_tag($a, &$body, &$inform, &$str_tags, $profile_uid, $tag) { +function handle_tag($a, &$body, &$access_tag, &$str_tags, $profile_uid, $tag) { $replaced = false; $r = null; - $termtype = ((strpos($tag,'#') === 0) ? TERM_HASHTAG : TERM_UNKNOWN); - $termtype = ((strpos($tag,'@') === 0) ? TERM_MENTION : $termtype); + + $termtype = ((strpos($tag,'#') === 0) ? TERM_HASHTAG : TERM_UNKNOWN); + $termtype = ((strpos($tag,'@') === 0) ? TERM_MENTION : $termtype); + $termtype = ((strpos($tag,'#^[') === 0) ? TERM_BOOKMARK : $termtype); + //is it a hash tag? if(strpos($tag,'#') === 0) { - //if the tag is replaced... - if(strpos($tag,'[url=')) + if(strpos($tag,'#^[') === 0) { + if(preg_match('/#\^\[(url|zrl)(.*?)\](.*?)\[\/(url|zrl)\]/',$tag,$match)) { + $basetag = $match[3]; + $url = ((substr($match[2],0,1) === '=') ? substr($match[2],1) : $match[3]); + $replaced = true; + + } + } + // if the tag is already replaced... + elseif(strpos($tag,'[zrl=')) { //...do nothing return $replaced; - //base tag has the tags name only - $basetag = str_replace('_',' ',substr($tag,1)); - //create text for link - $url = $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag); - $newtag = '#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]'; - //replace tag by the link - $body = str_replace($tag, $newtag, $body); - $replaced = true; + } + if($tag == '#getzot') { + $basetag = 'getzot'; + $url = 'https://redmatrix.me'; + $newtag = '#[zrl=' . $url . ']' . $basetag . '[/zrl]'; + $body = str_replace($tag,$newtag,$body); + $replaced = true; + } + if(! $replaced) { + + //base tag has the tags name only + if((substr($tag,0,7) === '#"') && (substr($tag,-6,6) === '"')) { + $basetag = substr($tag,7); + $basetag = substr($basetag,0,-6); + } + else + $basetag = str_replace('_',' ',substr($tag,1)); + + //create text for link + $url = $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag); + $newtag = '#[zrl=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/zrl]'; + //replace tag by the link + $body = str_replace($tag, $newtag, $body); + $replaced = true; + } //is the link already in str_tags? if(! stristr($str_tags,$newtag)) { //append or set str_tags @@ -823,113 +980,165 @@ function handle_tag($a, &$body, &$inform, &$str_tags, $profile_uid, $tag) { $str_tags .= ','; $str_tags .= $newtag; } - return array('replaced' => $replaced, 'termtype' => $termtype, 'url' => $url, 'contact' => $r[0]); + return array('replaced' => $replaced, 'termtype' => $termtype, 'term' => $basetag, 'url' => $url, 'contact' => $r[0]); } + //is it a person tag? + if(strpos($tag,'@') === 0) { + + // The @! tag will alter permissions + $exclusive = ((strpos($tag,'!') === 1) ? true : false); + //is it already replaced? - if(strpos($tag,'[url=')) + if(strpos($tag,'[zrl=')) return $replaced; - $stat = false; + //get the person's name - $name = substr($tag,1); - //is it a link or a full dfrn address? - if((strpos($name,'@')) || (strpos($name,'http://'))) { - $newname = $name; - //get the profile links - $links = @lrdd($name); - if(count($links)) { - //for all links, collect how is to inform and how's profile is to link - foreach($links as $link) { - if($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page') - $profile = $link['@attributes']['href']; - if($link['@attributes']['rel'] === 'salmon') { - if(strlen($inform)) - $inform .= ','; - $inform .= 'url:' . str_replace(',','%2c',$link['@attributes']['href']); - } - } - } - } else { //if it is a name rather than an address - $newname = $name; - $alias = ''; - $tagcid = 0; - //is it some generated name? - if(strrpos($newname,'+')) { - //get the id - $tagcid = intval(substr($newname,strrpos($newname,'+') + 1)); - //remove the next word from tag's name - if(strpos($name,' ')) { - $name = substr($name,0,strpos($name,' ')); - } + + $name = substr($tag,(($exclusive) ? 2 : 1)); // The name or name fragment we are going to replace + $newname = $name; // a copy that we can mess with + $tagcid = 0; + + $r = null; + + // is it some generated name? + + $forum = false; + $trailing_plus_name = false; + + // @channel+ is a forum or network delivery tag + + if(substr($newname,-1,1) === '+') { + $forum = true; + $newname = substr($newname,0,-1); + } + + // Here we're looking for an address book entry as provided by the auto-completer + // of the form something+nnn where nnn is an abook_id or the first chars of xchan_hash + + if(strrpos($newname,'+')) { + //get the id + + if(strrpos($tagcid,' ')) + $tagcid = substr($tagcid,0,strrpos($tagcid,' ')); + + $tagcid = substr($newname,strrpos($newname,'+') + 1); + + if(strlen($tagcid) < 16) + $abook_id = intval($tagcid); + //remove the next word from tag's name + if(strpos($name,' ')) { + $name = substr($name,0,strpos($name,' ')); } - if($tagcid) { //if there was an id - //select contact with that id from the logged in user's contact list - $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($tagcid), + + if($abook_id) { // if there was an id + // select channel with that id from the logged in user's address book + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash + WHERE abook_id = %d AND abook_channel = %d LIMIT 1", + intval($abook_id), intval($profile_uid) ); } else { - $newname = str_replace('_',' ',$name); - - //select someone from this user's contacts by name - $r = q("SELECT * FROM `contact` WHERE `name` = '%s' AND `uid` = %d LIMIT 1", - dbesc($newname), - intval($profile_uid) + $r = q("SELECT * FROM xchan + WHERE xchan_hash like '%s%%' LIMIT 1", + dbesc($tagcid) ); + } + } - if(! $r) { - //select someone by attag or nick and the name passed in - $r = q("SELECT * FROM `contact` WHERE `attag` = '%s' OR `nick` = '%s' AND `uid` = %d ORDER BY `attag` DESC LIMIT 1", - dbesc($name), - dbesc($name), - intval($profile_uid) - ); - } + if(! $r) { + + // look for matching names in the address book + + // Two ways to deal with spaces - doube quote the name or use underscores + // we see this after input filtering so quotes have been html entity encoded + + if((substr($name,0,6) === '"') && (substr($name,-6,6) === '"')) { + $newname = substr($name,6); + $newname = substr($newname,0,-6); } -/* } elseif(strstr($name,'_') || strstr($name,' ')) { //no id - //get the real name + else $newname = str_replace('_',' ',$name); - //select someone from this user's contacts by name - $r = q("SELECT * FROM `contact` WHERE `name` = '%s' AND `uid` = %d LIMIT 1", - dbesc($newname), + + //select someone from this user's contacts by name + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash + WHERE xchan_name = '%s' AND abook_channel = %d LIMIT 1", + dbesc($newname), + intval($profile_uid) + ); + + if(! $r) { + //select someone by attag or nick and the name passed in + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash + WHERE xchan_addr like ('%s') AND abook_channel = %d LIMIT 1", + dbesc($newname . '@%'), intval($profile_uid) ); - } else { - //select someone by attag or nick and the name passed in - $r = q("SELECT * FROM `contact` WHERE `attag` = '%s' OR `nick` = '%s' AND `uid` = %d ORDER BY `attag` DESC LIMIT 1", - dbesc($name), - dbesc($name), + } + + if(! $r) { + + // it's possible somebody has a name ending with '+', which we stripped off as a forum indicator + // This is very rare but we want to get it right. + + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash + WHERE xchan_name = '%s' AND abook_channel = %d LIMIT 1", + dbesc($newname . '+'), intval($profile_uid) ); - }*/ - //$r is set, if someone could be selected - if(count($r)) { - $profile = $r[0]['url']; - //set newname to nick, find alias - if($r[0]['network'] === 'stat') { - $newname = $r[0]['nick']; - $stat = true; - if($r[0]['alias']) - $alias = $r[0]['alias']; - } - else - $newname = $r[0]['name']; - //add person's id to $inform - if(strlen($inform)) - $inform .= ','; - $inform .= 'cid:' . $r[0]['id']; + if($r) + $trailing_plus_name = true; + } + } + + // $r is set if we found something + + if($r) { + $profile = $r[0]['xchan_url']; + $newname = $r[0]['xchan_name']; + // add the channel's xchan_hash to $access_tag if exclusive + if($exclusive) { + $access_tag .= 'cid:' . $r[0]['xchan_hash']; } } - //if there is an url for this persons profile + else { + // check for a group/collection exclusion tag + + // note that we aren't setting $replaced even though we're replacing text. + // This tag isn't going to get a term attached to it. It's only used for + // access control. The link points to out own channel just so it doesn't look + // weird - as all the other tags are linked to something. + + if(local_user() && local_user() == $profile_uid) { + require_once('include/group.php'); + $grp = group_byname($profile_uid,$name); + if($grp) { + $g = q("select hash from groups where id = %d and visible = 1 limit 1", + intval($grp[0]['id']) + ); + if($g && $exclusive) { + $access_tag .= 'gid:' . $g[0]['hash']; + } + $channel = get_app()->get_channel(); + if($channel) { + $newtag = '@' . (($exclusive) ? '!' : '') . '[zrl=' . z_root() . '/channel/' . $channel['channel_address'] . ']' . $newname . '[/zrl]'; + $body = str_replace('@' . (($exclusive) ? '!' : '') . $name, $newtag, $body); + } + } + } + } + + // if there is an url for this channel + if(isset($profile)) { $replaced = true; //create profile link $profile = str_replace(',','%2c',$profile); $url = $profile; - $newtag = '@[url=' . $profile . ']' . $newname . '[/url]'; - $body = str_replace('@' . $name, $newtag, $body); + $newtag = '@' . (($exclusive) ? '!' : '') . '[zrl=' . $profile . ']' . $newname . (($forum && ! $trailing_plus_name) ? '+' : '') . '[/zrl]'; + $body = str_replace('@' . (($exclusive) ? '!' : '') . $name, $newtag, $body); //append tag to str_tags if(! stristr($str_tags,$newtag)) { if(strlen($str_tags)) @@ -938,8 +1147,7 @@ function handle_tag($a, &$body, &$inform, &$str_tags, $profile_uid, $tag) { } } } - - return array('replaced' => $replaced, 'termtype' => $termtype, 'url' => $url, 'contact' => $r[0]); + return array('replaced' => $replaced, 'termtype' => $termtype, 'term' => $newname, 'url' => $url, 'contact' => $r[0]); } @@ -948,15 +1156,18 @@ function fix_attached_photo_permissions($uid,$xchan_hash,$body, $str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny) { $match = null; - - if(preg_match_all("/\[img\](.*?)\[\/img\]/",$body,$match)) { - $images = $match[1]; + // match img and zmg image links + if(preg_match_all("/\[[zi]mg(.*?)\](.*?)\[\/[zi]mg\]/",$body,$match)) { + $images = $match[2]; if($images) { foreach($images as $image) { if(! stristr($image,get_app()->get_baseurl() . '/photo/')) continue; $image_uri = substr($image,strrpos($image,'/') + 1); - $image_uri = substr($image_uri,0, strpos($image_uri,'-')); + if(strpos($image_uri,'-') !== false) + $image_uri = substr($image_uri,0, strpos($image_uri,'-')); + if(strpos($image_uri,'.') !== false) + $image_uri = substr($image_uri,0, strpos($image_uri,'.')); if(! strlen($image_uri)) continue; $srch = '<' . $xchan_hash . '>'; @@ -971,15 +1182,38 @@ function fix_attached_photo_permissions($uid,$xchan_hash,$body, if($r) { $r = q("UPDATE photo SET allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' - WHERE resource_id = '%s' AND uid = %d AND album = '%s' ", + WHERE resource_id = '%s' AND uid = %d ", dbesc($str_contact_allow), dbesc($str_group_allow), dbesc($str_contact_deny), dbesc($str_group_deny), dbesc($image_uri), - intval($uid), - dbesc( t('Wall Photos')) + intval($uid) + ); + + // also update the linked item (which is probably invisible) + + $r = q("select id from item + WHERE allow_cid = '%s' AND allow_gid = '' AND deny_cid = '' AND deny_gid = '' + AND resource_id = '%s' and resource_type = 'photo' AND uid = %d LIMIT 1", + dbesc($srch), + dbesc($image_uri), + intval($uid) ); + if($r) { + $private = (($str_contact_allow || $str_group_allow || $str_contact_deny || $str_group_deny) ? true : false); + + $r = q("UPDATE item SET allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', item_private = %d + WHERE id = %d AND uid = %d limit 1", + dbesc($str_contact_allow), + dbesc($str_group_allow), + dbesc($str_contact_deny), + dbesc($str_group_deny), + intval($private), + intval($r[0]['id']), + intval($uid) + ); + } } } } @@ -987,7 +1221,7 @@ function fix_attached_photo_permissions($uid,$xchan_hash,$body, } -function fix_attached_file_permissions($uid,$xchan_hash,$body, +function fix_attached_file_permissions($channel,$observer_hash,$body, $str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny) { $match = false; @@ -996,25 +1230,55 @@ function fix_attached_file_permissions($uid,$xchan_hash,$body, $attaches = $match[1]; if($attaches) { foreach($attaches as $attach) { - $r = q("select * from attach where uid = %d and hash = '%s' - and allow_cid = '%s' and allow_gid = '' and deny_cid = '' and deny_gid = '' limit 1", - intval($uid), - dbesc($attach), - dbesc('<' . $xchan_hash . '>') - ); - if($r) { - $r = q("UPDATE attach - SET allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' - WHERE uid = %d AND hash = '%s' LIMIT 1", - dbesc($str_contact_allow), - dbesc($str_group_allow), - dbesc($str_contact_deny), - dbesc($str_group_deny), - intval($uid), - dbesc($attach) - ); - } + $hash = substr($attach,0,strpos($attach,',')); + $rev = intval(substr($attach,strpos($attach,','))); + attach_store($channel,$observer_hash,$options = 'update', array( + 'hash' => $hash, + 'revision' => $rev, + 'allow_cid' => $str_contact_allow, + 'allow_gid' => $str_group_allow, + 'deny_cid' => $str_contact_deny, + 'deny_gid' => $str_group_deny + )); } } } } +function item_check_service_class($channel_id,$iswebpage) { + $ret = array('success' => false, $message => ''); + if ($iswebpage) { + $r = q("select count(i.id) as total from item i + right join channel c on (i.author_xchan=c.channel_hash and i.uid=c.channel_id ) + and i.parent=i.id and (i.item_restrict & %d) and not (i.item_restrict & %d) and i.uid= %d ", + intval(ITEM_WEBPAGE), + intval(ITEM_DELETED), + intval($channel_id) + ); + } + else { + $r = q("select count(i.id) as total from item i + right join channel c on (i.author_xchan=c.channel_hash and i.uid=c.channel_id ) + and i.parent=i.id and (i.item_restrict=0) and i.uid= %d ", + intval($channel_id) + ); + } + if(! ($r && count($r))) { + $ret['message'] = t('Unable to obtain identity information from database'); + return $ret; + } + if (!$iswebpage) { + if(! service_class_allows($channel_id,'total_items',$r[0]['total'])) { + $result['message'] .= upgrade_message().sprintf(t("You have reached your limit of %1$.0f top level posts."),$r[0]['total']); + return $result; + } + } + else { + if(! service_class_allows($channel_id,'total_pages',$r[0]['total'])) { + $result['message'] .= upgrade_message().sprintf(t("You have reached your limit of %1$.0f webpages."),$r[0]['total']); + return $result; + } + } + + $ret['success'] = true; + return $ret; +} diff --git a/mod/lang.php b/mod/lang.php new file mode 100644 index 000000000..fba5f9c73 --- /dev/null +++ b/mod/lang.php @@ -0,0 +1,6 @@ +<?php + +function lang_content(&$a) { + return lang_selector(); +} + diff --git a/mod/layouts.php b/mod/layouts.php new file mode 100644 index 000000000..318e6e29f --- /dev/null +++ b/mod/layouts.php @@ -0,0 +1,122 @@ +<?php + +function layouts_content(&$a) { + + if(argc() > 1) + $which = argv(1); + else { + notice( t('Requested profile is not available.') . EOL ); + $a->error = 404; + return; + } + + profile_load($a,$which,0); + + + // Figure out who the page owner is. + $r = q("select channel_id from channel where channel_address = '%s'", + dbesc($which) + ); + if($r) { + $owner = intval($r[0]['channel_id']); + } + + // Block design features from visitors + + if((! local_user()) || (local_user() != $owner)) { + notice( t('Permission denied.') . EOL); + return; + } + + // Get the observer, check their permissions + + $observer = $a->get_observer(); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + $perms = get_all_perms($owner,$ob_hash); + + if(! $perms['write_pages']) { + notice( t('Permission denied.') . EOL); + return; + } + + if((argc() > 3) && (argv(2) === 'share') && (argv(3))) { + $r = q("select sid, service, mimetype, title, body from item_id left join item on item.id = item_id.iid where item_id.uid = %d and item.mid = '%s' and service = 'PDL' order by sid asc", + intval($owner), + dbesc(argv(3)) + ); + if($r) { + header('Content-type: application/x-redmatrix-layout'); + header('Content-disposition: attachment; filename="' . $r[0]['sid'] . '.pdl"'); + echo json_encode($r); + killme(); + + } + } + + $tabs = array( + array( + 'label' => t('Layout Help'), + 'url' => 'help/Comanche', + 'sel' => '', + 'title' => t('Help with this feature'), + 'id' => 'layout-help-tab', + )); + + + $o .= replace_macros(get_markup_template('common_tabs.tpl'),array('$tabs' => $tabs)); + + + // Create a status editor (for now - we'll need a WYSIWYG eventually) to create pages + // Nickname is set to the observers xchan, and profile_uid to the owners. This lets you post pages at other people's channels. + + require_once ('include/conversation.php'); + + $x = array( + 'webpage' => ITEM_PDL, + 'is_owner' => true, + 'nickname' => $a->profile['channel_address'], + 'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), + 'bang' => (($group || $cid) ? '!' : ''), + 'showacl' => false, + 'visitor' => false, + 'nopreview' => 1, + 'ptlabel' => t('Layout Name'), + 'profile_uid' => intval($owner), + ); + + $o .= status_editor($a,$x); + + // Get a list of blocks. We can't display all them because endless scroll makes that unusable, so just list titles and an edit link. + // TODO - this should be replaced with pagelist_widget + + $r = q("select iid, sid, mid from item_id left join item on item.id = item_id.iid where item_id.uid = %d and service = 'PDL' order by sid asc", + intval($owner) + ); + + $pages = null; + + if($r) { + $pages = array(); + foreach($r as $rr) { + $pages[$rr['iid']][] = array('url' => $rr['iid'],'title' => $rr['sid'], 'mid' => $rr['mid']); + } + } + + + //Build the base URL for edit links + $url = z_root() . "/editlayout/" . $which; + + return $o . replace_macros(get_markup_template("layoutlist.tpl"), array( + '$baseurl' => $url, + '$edit' => t('Edit'), + '$share' => t('Share'), + '$pages' => $pages, + '$channel' => $which, + '$view' => t('View'), + '$preview' => '1', + + )); + + +} diff --git a/mod/like.php b/mod/like.php index 30d64d4ca..ececb31c7 100755 --- a/mod/like.php +++ b/mod/like.php @@ -10,14 +10,11 @@ function like_content(&$a) { $observer = $a->get_observer(); - - $verb = notags(trim($_GET['verb'])); if(! $verb) $verb = 'like'; - switch($verb) { case 'like': case 'unlike': @@ -32,149 +29,263 @@ function like_content(&$a) { break; } + $extended_like = false; + $object = $target = null; + $post_type = ''; + $objtype = ''; + + if(argc() == 3) { + + if(! $observer) + killme(); + + $extended_like = true; + $obj_type = argv(1); + $obj_id = argv(2); + $public = true; + + if($obj_type == 'profile') { + $r = q("select * from profile where profile_guid = '%s' limit 1", + dbesc(argv(2)) + ); + if(! $r) + killme(); + $owner_uid = $r[0]['uid']; + if($r[0]['is_default']) + $public = true; + if(! $public) { + $d = q("select abook_xchan from abook where abook_profile = '%s' and abook_channel = %d", + dbesc($r[0]['profile_guid']), + intval($owner_uid) + ); + if(! $d) { + // forgery - illegal + killme(); + } + // $d now contains a list of those who can see this profile - only send the status notification + // to them. + $allow_cid = $allow_gid = $deny_cid = $deny_gid = ''; + foreach($d as $dd) { + $allow_gid .= '<' . $dd['abook_xchan'] . '>'; + } + } + $post_type = t('channel'); + $objtype = ACTIVITY_OBJ_PROFILE; + + + } + elseif($obj_type == 'thing') { + + $r = q("select * from obj left join term on obj_obj = term_hash where term_hash != '' + and obj_type = %d and term_hash = '%s' limit 1", + intval(TERM_OBJ_THING), + dbesc(argv(2)) + ); + + if(! $r) + killme(); + + $owner_uid = $r[0]['obj_channel']; + + $allow_cid = $r[0]['allow_cid']; + $allow_gid = $r[0]['allow_gid']; + $deny_cid = $r[0]['deny_cid']; + $deny_gid = $r[0]['deny_gid']; + if($allow_cid || $allow_gid || $deny_cid || $deny_gid) + $public = false; + + $post_type = t('thing'); + $objtype = ACTIVITY_OBJ_PROFILE; + $tgttype = ACTIVITY_OBJ_THING; + + $links = array(); + $links[] = array('rel' => 'alternate', 'type' => 'text/html', + 'href' => z_root() . '/thing/' . $r[0]['term_hash']); + if($r[0]['imgurl']) + $links[] = array('rel' => 'photo', 'href' => $r[0]['imgurl']); + + $target = json_encode(array( + 'type' => $tgttype, + 'title' => $r[0]['term'], + 'id' => z_root() . '/thing/' . $r[0]['term_hash'], + 'link' => $links + )); + + $plink = '[zrl=' . z_root() . '/thing/' . $r[0]['term_hash'] . ']' . $r[0]['term'] . '[/zrl]'; + + } + + if(! ($owner_uid && $r)) + killme(); + + // The resultant activity is going to be a wall-to-wall post, so make sure this is allowed + + $perms = get_all_perms($owner_uid,$observer['xchan_hash']); + + if(! ($perms['post_wall'] && $perms['view_profile'])) + killme(); + + $ch = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1", + intval($owner_uid) + ); + if(! $ch) + killme(); - $item_id = ((argc() > 1) ? notags(trim(argv(1))) : 0); - logger('like: verb ' . $verb . ' item ' . $item_id, LOGGER_DEBUG); + if(! $plink) + $plink = '[zrl=' . z_root() . '/profile/' . $ch[0]['channel_address'] . ']' . $post_type . '[/zrl]'; + + $links = array(); + $links[] = array('rel' => 'alternate', 'type' => 'text/html', + 'href' => z_root() . '/profile/' . $ch[0]['channel_address']); + $links[] = array('rel' => 'photo', 'type' => $ch[0]['xchan_photo_mimetype'], + 'href' => $ch[0]['xchan_photo_l']); + + $object = json_encode(array( + 'type' => ACTIVITY_OBJ_PROFILE, + 'title' => $ch[0]['channel_name'], + 'id' => $ch[0]['xchan_url'] . '/' . $ch[0]['xchan_hash'], + 'link' => $links + )); + + + // second like of the same thing is "undo" for the first like + + $z = q("select * from likes where channel_id = %d and liker = '%s' and verb = '%s' and target_type = '%s' and target_id = '%s' limit 1", + intval($ch[0]['channel_id']), + dbesc($observer['xchan_hash']), + dbesc($activity), + dbesc(($tgttype)?$tgttype:$objtype), + dbesc($obj_id) + ); + if($z) { + q("delete from likes where id = %d limit 1", + intval($z[0]['id']) + ); + drop_item($z[0]['iid'],false); + killme(); + } + } + else { - $r = q("SELECT * FROM item WHERE id = %d and item_restrict = 0 LIMIT 1", - dbesc($item_id) - ); + $item_id = ((argc() == 2) ? notags(trim(argv(1))) : 0); - if(! $item_id || (! $r)) { - logger('like: no item ' . $item_id); - killme(); - } + logger('like: verb ' . $verb . ' item ' . $item_id, LOGGER_DEBUG); - $item = $r[0]; - $owner_uid = $item['uid']; + $r = q("SELECT * FROM item WHERE id = %d and item_restrict = 0 LIMIT 1", + dbesc($item_id) + ); - if(! perm_is_allowed($owner_uid,$observer['xchan_hash'],'post_comments')) { - notice( t('Permission denied') . EOL); - killme(); - } + if(! $item_id || (! $r)) { + logger('like: no item ' . $item_id); + killme(); + } - $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($item['owner_xchan']) - ); - if($r) - $thread_owner = $r[0]; - else - killme(); - - - $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($item['author_xchan']) - ); - if($r) - $item_author = $r[0]; - else - killme(); - - - -// fixme -// if(! $item['wall']) { - // The top level post may have been written by somebody on another system - -// $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", -// intval($item['contact-id']), -// intval($item['uid']) -// ); -// if(! count($r)) -// return; -// if(! $r[0]['self']) -// $thread_owner = $r[0]; -// } - - // this represents the post owner on this system. - -// $r = q("SELECT `contact`.*, `user`.`nickname` FROM `contact` LEFT JOIN `user` ON `contact`.`uid` = `user`.`uid` -// WHERE `contact`.`self` = 1 AND `contact`.`uid` = %d LIMIT 1", -// intval($owner_uid) -// ); -// if(count($r)) -// $owner = $r[0]; - -// if(! $owner) { -// logger('like: no owner'); -// return; -// } - -// if(! $thread_owner) -// $thread_owner = $owner; - - - // This represents the person posting - -// if((local_user()) && (local_user() == $owner_uid)) { -// $contact = $owner; -// } -// else { -// $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", -// intval($_SESSION['visitor_id']), -// intval($owner_uid) -// ); -// if(count($r)) -// $contact = $r[0]; -// } -// if(! $contact) { -// return; -// } - - - $r = q("SELECT * FROM item WHERE verb = '%s' AND item_restrict = 0 - AND owner_xchan = '%s' AND ( parent = %d OR thr_parent = '%s') LIMIT 1", - dbesc($activity), - dbesc($thread_owner['xchan_hash']), - intval($item_id), - dbesc($item['uri']) - ); - if($r) { - $like_item = $r[0]; - - // Already liked/disliked it, delete it - - $r = q("UPDATE item SET item_restrict = ( item_restrict ^ %d ), changed = '%s' WHERE id = %d LIMIT 1", - intval(ITEM_DELETED), - dbesc(datetime_convert()), - intval($like_item['id']) + + $item = $r[0]; + $owner_uid = $item['uid']; + $owner_aid = $item['aid']; + + + $sys = get_sys_channel(); + + + // if this is a "discover" item, (item['uid'] is the sys channel), + // fallback to the item comment policy, which should've been + // respected when generating the conversation thread. + // Even if the activity is rejected by the item owner, it should still get attached + // to the local discover conversation on this site. + + if(($owner_uid != $sys['channel_id']) && (! perm_is_allowed($owner_uid,$observer['xchan_hash'],'post_comments'))) { + notice( t('Permission denied') . EOL); + killme(); + } + + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($item['owner_xchan']) ); + if($r) + $thread_owner = $r[0]; + else + killme(); - proc_run('php',"include/notifier.php","like",$like_item['id']); - return; - } + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($item['author_xchan']) + ); + if($r) + $item_author = $r[0]; + else + killme(); + + + $r = q("SELECT * FROM item WHERE verb = '%s' AND item_restrict = 0 + AND author_xchan = '%s' AND ( parent = %d OR thr_parent = '%s') LIMIT 1", + dbesc($activity), + dbesc($observer['xchan_hash']), + intval($item_id), + dbesc($item['mid']) + ); + if($r) { + $like_item = $r[0]; + // Already liked/disliked it, delete it + $r = q("UPDATE item SET item_restrict = ( item_restrict ^ %d ), changed = '%s' WHERE id = %d LIMIT 1", + intval(ITEM_DELETED), + dbesc(datetime_convert()), + intval($like_item['id']) + ); - $uri = item_message_id(); + proc_run('php',"include/notifier.php","like",$like_item['id']); + return; + } - $post_type = (($item['resource_id'] === 'photo') ? $t('photo') : t('status')); + } - $links = array(array('rel' => 'alternate','type' => 'text/html', - 'href' => z_root() . '/display/' . $item['uri'])); - $objtype = (($item['resource_id'] === 'photo') ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE ); + $mid = item_message_id(); - $body = $item['body']; + if($extended_like) { + $item_flags = ITEM_THREAD_TOP|ITEM_ORIGIN|ITEM_WALL; - $obj = json_encode(array( - 'type' => $objtype, - 'id' => $item['uri'], - 'link' => $links, - 'title' => $item['title'], - 'content' => $item['body'], - 'author' => array( - 'name' => $item_author['xchan_name'], - 'address' => $item_author['xchan_addr'], - 'guid' => $item_author['xchan_guid'], - 'guid_sig' => $item_author['xchan_guid_sig'], - 'link' => array( - array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item_author['xchan_url']), - array('rel' => 'photo', 'type' => $item_author['xchan_photo_mimetype'], 'href' => $item_author['xchan_photo_m'])), - ), - )); + } + else { + $post_type = (($item['resource_type'] === 'photo') ? t('photo') : t('status')); + + $links = array(array('rel' => 'alternate','type' => 'text/html', 'href' => $item['plink'])); + $objtype = (($item['resource_type'] === 'photo') ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE ); + + $body = $item['body']; + + $object = json_encode(array( + 'type' => $objtype, + 'id' => $item['mid'], + 'parent' => (($item['thr_parent']) ? $item['thr_parent'] : $item['parent_mid']), + 'link' => $links, + 'title' => $item['title'], + 'content' => $item['body'], + 'created' => $item['created'], + 'edited' => $item['edited'], + 'author' => array( + 'name' => $item_author['xchan_name'], + 'address' => $item_author['xchan_addr'], + 'guid' => $item_author['xchan_guid'], + 'guid_sig' => $item_author['xchan_guid_sig'], + 'link' => array( + array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item_author['xchan_url']), + array('rel' => 'photo', 'type' => $item_author['xchan_photo_mimetype'], 'href' => $item_author['xchan_photo_m'])), + ), + )); + + if(! ($item['item_flags'] & ITEM_THREAD_TOP)) + $post_type = 'comment'; + + $item_flags = ITEM_ORIGIN | ITEM_NOTSHOWN; + if($item['item_flags'] & ITEM_WALL) + $item_flags |= ITEM_WALL; + + } if($verb === 'like') $bodyverb = t('%1$s likes %2$s\'s %3$s'); @@ -182,46 +293,84 @@ function like_content(&$a) { $bodyverb = t('%1$s doesn\'t like %2$s\'s %3$s'); if(! isset($bodyverb)) - return; + killme(); - $item_flags = ITEM_ORIGIN; - if($item['item_flags'] & ITEM_WALL) - $item_flags |= ITEM_WALL; - $arr = array(); - $arr['uri'] = $uri; + if($extended_like) { + $ulink = '[zrl=' . $ch[0]['xchan_url'] . ']' . $ch[0]['xchan_name'] . '[/zrl]'; + $alink = '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]'; + $private = (($public) ? 0 : 1); + } + else { + $arr['parent'] = $item['id']; + $arr['thr_parent'] = $item['mid']; + $ulink = '[zrl=' . $item_author['xchan_url'] . ']' . $item_author['xchan_name'] . '[/zrl]'; + $alink = '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]'; + $plink = '[zrl=' . $a->get_baseurl() . '/display/' . $item['mid'] . ']' . $post_type . '[/zrl]'; + $allow_cid = $item['allow_cid']; + $allow_gid = $item['allow_gid']; + $deny_cid = $item['deny_cid']; + $deny_gid = $item['deny_gid']; + $private = $item['private']; + + } + + + $arr['mid'] = $mid; + $arr['aid'] = (($extended_like) ? $ch[0]['channel_account_id'] : $owner_aid); $arr['uid'] = $owner_uid; $arr['item_flags'] = $item_flags; - $arr['parent'] = $item['id']; - $arr['parent_uri'] = $item['uri']; - $arr['thr_parent'] = $item['uri']; - $arr['owner_xchan'] = $thread_owner['xchan_hash']; + $arr['parent_mid'] = (($extended_like) ? $mid : $item['mid']); + $arr['owner_xchan'] = (($extended_like) ? $ch[0]['xchan_hash'] : $thread_owner['xchan_hash']); $arr['author_xchan'] = $observer['xchan_hash']; - $ulink = '[url=' . $item_owner['xchan_url'] . ']' . $item_owner['xchan_name'] . '[/url]'; - $alink = '[url=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/url]'; - $plink = '[url=' . $a->get_baseurl() . '/display/' . $item['uri'] . ']' . $post_type . '[/url]'; - - $arr['body'] = sprintf( $bodyverb, $ulink, $alink, $plink ); + $arr['body'] = sprintf( $bodyverb, $alink, $ulink, $plink ); + if($obj_type === 'thing' && $r[0]['imgurl']) { + $arr['body'] .= "\n\n[zmg=80x80]" . $r[0]['imgurl'] . '[/zmg]'; + } + $arr['verb'] = $activity; $arr['obj_type'] = $objtype; - $arr['object'] = $obj; + $arr['object'] = $object; + + if($target) { + $arr['tgt_type'] = $tgttype; + $arr['target'] = $target; + } - $arr['allow_cid'] = $item['allow_cid']; - $arr['allow_gid'] = $item['allow_gid']; - $arr['deny_cid'] = $item['deny_cid']; - $arr['deny_gid'] = $item['deny_gid']; + $arr['allow_cid'] = $allow_cid; + $arr['allow_gid'] = $allow_gid; + $arr['deny_cid'] = $deny_cid; + $arr['deny_gid'] = $deny_gid; + $arr['item_private'] = $private; - $post_id = item_store($arr); + + $post = item_store($arr); + $post_id = $post['item_id']; $arr['id'] = $post_id; call_hooks('post_local_end', $arr); + + if($extended_like) { + $r = q("insert into likes (channel_id,liker,likee,iid,verb,target_type,target_id,target) values (%d,'%s','%s',%d,'%s','%s','%s','%s')", + intval($ch[0]['channel_id']), + dbesc($observer['xchan_hash']), + dbesc($ch[0]['channel_hash']), + intval($post_id), + dbesc($activity), + dbesc(($tgttype)?$tgttype:$objtype), + dbesc($obj_id), + dbesc(json_encode(($target)?$target:$object)) + ); + }; + + proc_run('php',"include/notifier.php","like","$post_id"); killme(); diff --git a/mod/lockview.php b/mod/lockview.php index 0307103f8..0ea708c80 100644 --- a/mod/lockview.php +++ b/mod/lockview.php @@ -3,12 +3,12 @@ function lockview_content(&$a) { - $type = (($a->argc > 1) ? $a->argv[1] : 0); + $type = ((argc() > 1) ? argv(1) : 0); if (is_numeric($type)) { $item_id = intval($type); $type='item'; } else { - $item_id = (($a->argc > 2) ? intval($a->argv[2]) : 0); + $item_id = ((argc() > 2) ? intval(argv(2)) : 0); } if(! $item_id) @@ -17,21 +17,23 @@ function lockview_content(&$a) { if (!in_array($type, array('item','photo','event'))) killme(); - $r = q("SELECT * FROM `%s` WHERE `id` = %d LIMIT 1", + $r = q("SELECT * FROM %s WHERE id = %d LIMIT 1", dbesc($type), intval($item_id) ); - if(! count($r)) + if(! $r) killme(); + $item = $r[0]; - if($item['uid'] != local_user()) - killme(); + if($item['uid'] != local_user()) { + echo '<li>' . t('Remote privacy information not available.') . '</li>'; + killme(); + } - if(($item['private'] == 1) && (! strlen($item['allow_cid'])) && (! strlen($item['allow_gid'])) + if(($item['item_private'] == 1) && (! strlen($item['allow_cid'])) && (! strlen($item['allow_gid'])) && (! strlen($item['deny_cid'])) && (! strlen($item['deny_gid']))) { - - echo t('Remote privacy information not available.') . '<br />'; + echo '<li>' . t('Remote privacy information not available.') . '</li>'; killme(); } @@ -40,46 +42,40 @@ function lockview_content(&$a) { $deny_users = expand_acl($item['deny_cid']); $deny_groups = expand_acl($item['deny_gid']); - $o = t('Visible to:') . '<br />'; + $o = '<li>' . t('Visible to:') . '</li>'; $l = array(); + stringify_array_elms($allowed_groups,true); + stringify_array_elms($allowed_users,true); + stringify_array_elms($deny_groups,true); + stringify_array_elms($deny_users,true); + if(count($allowed_groups)) { - $r = q("SELECT `name` FROM `group` WHERE `id` IN ( %s )", - dbesc(implode(', ', $allowed_groups)) - ); - if(count($r)) + $r = q("SELECT name FROM `groups` WHERE hash IN ( " . implode(', ', $allowed_groups) . " )"); + if($r) foreach($r as $rr) - $l[] = '<b>' . $rr['name'] . '</b>'; + $l[] = '<li><b>' . $rr['name'] . '</b></li>'; } if(count($allowed_users)) { - $r = q("SELECT `name` FROM `contact` WHERE `id` IN ( %s )", - dbesc(implode(', ',$allowed_users)) - ); - if(count($r)) + $r = q("SELECT xchan_name FROM xchan WHERE xchan_hash IN ( " . implode(', ',$allowed_users) . " )"); + if($r) foreach($r as $rr) - $l[] = $rr['name']; - + $l[] = '<li>' . $rr['xchan_name'] . '</li>'; } - if(count($deny_groups)) { - $r = q("SELECT `name` FROM `group` WHERE `id` IN ( %s )", - dbesc(implode(', ', $deny_groups)) - ); - if(count($r)) + $r = q("SELECT name FROM `groups` WHERE hash IN ( " . implode(', ', $deny_groups) . " )"); + if($r) foreach($r as $rr) - $l[] = '<b><strike>' . $rr['name'] . '</strike></b>'; + $l[] = '<li><b><strike>' . $rr['name'] . '</strike></b></li>'; } if(count($deny_users)) { - $r = q("SELECT `name` FROM `contact` WHERE `id` IN ( %s )", - dbesc(implode(', ',$deny_users)) - ); - if(count($r)) + $r = q("SELECT xchan_name FROM xchan WHERE xchan_hash IN ( " . implode(', ', $deny_users) . " )"); + if($r) foreach($r as $rr) - $l[] = '<strike>' . $rr['name'] . '</strike>'; - + $l[] = '<li><strike>' . $rr['xchan_name'] . '</strike></li>'; } - echo $o . implode(', ', $l); + echo $o . implode($l); killme(); } diff --git a/mod/lostpass.php b/mod/lostpass.php index 57e6d6965..dd7c7a7d5 100644 --- a/mod/lostpass.php +++ b/mod/lostpass.php @@ -7,42 +7,41 @@ function lostpass_post(&$a) { if(! $loginame) goaway(z_root()); - $r = q("SELECT * FROM `user` WHERE ( `email` = '%s' OR `nickname` = '%s' ) AND `verified` = 1 AND `blocked` = 0 LIMIT 1", - dbesc($loginame), + $r = q("SELECT * FROM account WHERE account_email = '%s' LIMIT 1", dbesc($loginame) ); - if(! count($r)) { + if(! $r) { notice( t('No valid account found.') . EOL); goaway(z_root()); } - $uid = $r[0]['uid']; - $username = $r[0]['username']; - $email = $r[0]['email']; + $aid = $r[0]['account_id']; + $email = $r[0]['account_email']; - $new_password = autoname(12) . mt_rand(100,9999); - $new_password_encoded = hash('whirlpool',$new_password); + $hash = random_string(); - $r = q("UPDATE `user` SET `pwdreset` = '%s' WHERE `uid` = %d LIMIT 1", - dbesc($new_password_encoded), - intval($uid) + $r = q("UPDATE account SET account_reset = '%s' WHERE account_id = %d LIMIT 1", + dbesc($hash), + intval($aid) ); if($r) info( t('Password reset request issued. Check your email.') . EOL); $email_tpl = get_intltext_template("lostpass_eml.tpl"); - $email_tpl = replace_macros($email_tpl, array( - '$sitename' => $a->config['sitename'], + $message = replace_macros($email_tpl, array( + '$sitename' => get_config('system','sitename'), '$siteurl' => $a->get_baseurl(), - '$username' => $username, + '$username' => sprintf( t('Site Member (%s)'), $email), '$email' => $email, - '$reset_link' => $a->get_baseurl() . '/lostpass?verify=' . $new_password + '$reset_link' => $a->get_baseurl() . '/lostpass?verify=' . $hash )); - $res = mail($email, sprintf( t('Password reset requested at %s'),$a->config['sitename']), - $email_tpl, - 'From: ' . t('Administrator') . '@' . $_SERVER['SERVER_NAME'] . "\n" + $subject = email_header_encode(sprintf( t('Password reset requested at %s'),get_config('system','sitename')), 'UTF-8'); + + $res = mail($email, $subject , + $message, + 'From: Administrator@' . $_SERVER['SERVER_NAME'] . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit' ); @@ -56,27 +55,30 @@ function lostpass_content(&$a) { if(x($_GET,'verify')) { $verify = $_GET['verify']; - $hash = hash('whirlpool', $verify); - $r = q("SELECT * FROM `user` WHERE `pwdreset` = '%s' LIMIT 1", - dbesc($hash) + $r = q("SELECT * FROM account WHERE account_reset = '%s' LIMIT 1", + dbesc($verify) ); - if(! count($r)) { - notice( t("Request could not be verified. \x28You may have previously submitted it.\x29 Password reset failed.") . EOL); + if(! $r) { + notice( t("Request could not be verified. (You may have previously submitted it.) Password reset failed.") . EOL); goaway(z_root()); return; } - $uid = $r[0]['uid']; - $username = $r[0]['username']; - $email = $r[0]['email']; + + $aid = $r[0]['account_id']; + $email = $r[0]['account_email']; $new_password = autoname(6) . mt_rand(100,9999); - $new_password_encoded = hash('whirlpool',$new_password); - $r = q("UPDATE `user` SET `password` = '%s', `pwdreset` = '' WHERE `uid` = %d LIMIT 1", - dbesc($new_password_encoded), - intval($uid) + $salt = random_string(32); + $password_encoded = hash('whirlpool', $salt . $new_password); + + $r = q("UPDATE account SET account_salt = '%s', account_password = '%s', account_reset = '' where account_id = %d limit 1", + dbesc($salt), + dbesc($password_encoded), + intval($aid) ); + if($r) { $tpl = get_markup_template('pwdreset.tpl'); $o .= replace_macros($tpl,array( @@ -90,21 +92,22 @@ function lostpass_content(&$a) { '$baseurl' => $a->get_baseurl() )); - info("Your password has been reset." . EOL); - - + + info("Your password has been reset." . EOL); $email_tpl = get_intltext_template("passchanged_eml.tpl"); - $email_tpl = replace_macros($email_tpl, array( + $message = replace_macros($email_tpl, array( '$sitename' => $a->config['sitename'], '$siteurl' => $a->get_baseurl(), - '$username' => $username, + '$username' => sprintf( t('Site Member (%s)'), $email), '$email' => $email, '$new_password' => $new_password, '$uid' => $newuid )); - $res = mail($email,"Your password has changed at {$a->config['sitename']}",$email_tpl, - 'From: ' . t('Administrator') . '@' . $_SERVER['SERVER_NAME'] . "\n" + $subject = email_header_encode( sprintf( t('Your password has changed at %s'), get_config('system','sitename')), 'UTF-8'); + + $res = mail($email,$subject,$message, + 'From: ' . 'Administrator@' . $_SERVER['SERVER_NAME'] . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit' ); @@ -118,7 +121,7 @@ function lostpass_content(&$a) { $o .= replace_macros($tpl,array( '$title' => t('Forgot your Password?'), '$desc' => t('Enter your email address and submit to have your password reset. Then check your email for further instructions.'), - '$name' => t('Nickname or Email: '), + '$name' => t('Email Address'), '$submit' => t('Reset') )); diff --git a/mod/magic.php b/mod/magic.php index b74130005..aead559a7 100644 --- a/mod/magic.php +++ b/mod/magic.php @@ -4,87 +4,143 @@ function magic_init(&$a) { - $url = ((x($_REQUEST,'url')) ? $_REQUEST['url'] : ''); + $ret = array('success' => false, 'url' => '', 'message' => ''); + logger('mod_magic: invoked', LOGGER_DEBUG); + + logger('mod_magic: args: ' . print_r($_REQUEST,true),LOGGER_DATA); + $addr = ((x($_REQUEST,'addr')) ? $_REQUEST['addr'] : ''); $hash = ((x($_REQUEST,'hash')) ? $_REQUEST['hash'] : ''); $dest = ((x($_REQUEST,'dest')) ? $_REQUEST['dest'] : ''); + $test = ((x($_REQUEST,'test')) ? intval($_REQUEST['test']) : 0); + $rev = ((x($_REQUEST,'rev')) ? intval($_REQUEST['rev']) : 0); - if(local_user()) { - - if($hash) { - $x = q("select xchan.xchan_url, hubloc.* from xchan left join hubloc on xchan_hash = hubloc_hash - where hublock_hash = '%s' and (hubloc_flags & %d) limit 1", - intval(HUBLOC_FLAGS_PRIMARY) - ); + $parsed = parse_url($dest); + if(! $parsed) { + if($test) { + $ret['message'] .= 'could not parse ' . $dest . EOL; + return($ret); } - elseif($addr) { - $x = q("select hubloc.* from xchan left join hubloc on xchan_hash = hubloc_hash - where xchan_addr = '%s' and (hubloc_flags & %d) limit 1", - dbesc($addr), - intval(HUBLOC_FLAGS_PRIMARY) + goaway($dest); + } + + $basepath = $parsed['scheme'] . '://' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : ''); + + $x = q("select * from hubloc where hubloc_url = '%s' order by hubloc_connected desc limit 1", + dbesc($basepath) + ); + + if(! $x) { + + /* + * We have no records for, or prior communications with this hub. + * If an address was supplied, let's finger them to create a hub record. + * Otherwise we'll use the special address '[system]' which will return + * either a system channel or the first available normal channel. We don't + * really care about what channel is returned - we need the hub information + * from that response so that we can create signed auth packets destined + * for that hub. + * + */ + + $ret = zot_finger((($addr) ? $addr : '[system]@' . $parsed['host']),null); + if($ret['success']) { + $j = json_decode($ret['body'],true); + if($j) + import_xchan($j); + + // Now try again + + $x = q("select * from hubloc where hubloc_url = '%s' order by hubloc_connected desc limit 1", + dbesc($basepath) ); } + } - if(! $x) { - notice( t('Channel not found.') . EOL); + if(! $x) { + if($rev) + goaway($dest); + else { + logger('mod_magic: no channels found for requested hub.' . print_r($_REQUEST,true)); + if($test) { + $ret['message'] .= 'This site has no previous connections with ' . $basepath . EOL; + return $ret; + } + notice( t('Hub not found.') . EOL); return; } + } + + // This is ready-made for a plugin that provides a blacklist or "ask me" before blindly authenticating. + // By default, we'll proceed without asking. + + $arr = array( + 'channel_id' => local_user(), + 'xchan' => $x[0], + 'destination' => $dest, + 'proceed' => true + ); - if($x[0]['hubloc_url'] === z_root()) { - $webbie = substr($x[0]['hubloc_addr'],0,strpos('@',$x[0]['hubloc_addr'])); - switch($dest) { - case 'channel': - $desturl = z_root() . '/channel/' . $webbie; - break; - case 'photos': - $desturl = z_root() . '/photos/' . $webbie; - break; - case 'profile': - $desturl = z_root() . '/profile/' . $webbie; - break; - default: - $desturl = $dest; - break; - } - // We are already authenticated on this site and a registered observer. - // Just redirect. - goaway($desturl); + call_hooks('magic_auth',$arr); + $dest = $arr['destination']; + if(! $arr['proceed']) { + if($test) { + $ret['message'] .= 'cancelled by plugin.' . EOL; + return $ret; } + goaway($dest); + } - $token = random_string(); + if((get_observer_hash()) && ($x[0]['hubloc_url'] === z_root())) { + // We are already authenticated on this site and a registered observer. + // Just redirect. + if($test) { + $ret['success'] = true; + $ret['message'] .= 'Local site - you are already authenticated.' . EOL; + return $ret; + } + goaway($dest); + } - $recip = array(array('guid' => $x[0]['hubloc_guid'],'guid_sig' => $x[0]['hubloc_guid_sig'])); - $channel = $a->get_channel(); - $hash = random_string(); + if(local_user()) { + $channel = $a->get_channel(); + + $token = random_string(); + $token_sig = base64url_encode(rsa_sign($token,$channel['channel_prvkey'])); + + $channel['token'] = $token; + $channel['token_sig'] = $token_sig; $r = q("insert into verify ( type, channel, token, meta, created) values ('%s','%d','%s','%s','%s')", dbesc('auth'), intval($channel['channel_id']), dbesc($token), - dbesc($hubloc['hubloc_hash']), + dbesc($x[0]['hubloc_url']), dbesc(datetime_convert()) ); - $packet = zot_build_packet($channel,'auth',$recip,$x[0]['hubloc_sitekey'],$hash); - $result = zot_zot($x[0]['hubloc_callback'],$packet); - if($result['success']) { - $j = json_decode($result['body'],true); - if($j['iv']) { - $y = aes_unencapsulate($j,$channel['prvkey']); - $j = json_decode($y,true); - } - if($j['token'] && $j['ticket'] && $j['token'] === $token) { - $r = q("delete from verify where token = '%s' and type = '%s' and channel = %d limit 1", - dbesc($token), - dbesc('auth'), - intval($channel['channel_id']) - ); - goaway($x[0]['callback'] . '?f=&ticket=' . $ticket . '&dest=' . $dest); - } + $target_url = $x[0]['hubloc_callback'] . '/?f=&auth=' . urlencode($channel['channel_address'] . '@' . $a->get_hostname()) + . '&sec=' . $token . '&dest=' . urlencode($dest) . '&version=' . ZOT_REVISION; + + logger('mod_magic: redirecting to: ' . $target_url, LOGGER_DEBUG); + + if($test) { + $ret['success'] = true; + $ret['url'] = $target_url; + $ret['message'] = 'token ' . $token . ' created for channel ' . $channel['channel_id'] . ' for url ' . $x[0]['hubloc_url'] . EOL; + return $ret; } - goaway($dest); + + goaway($target_url); + } - goaway(z_root()); + if($test) { + $ret['message'] = 'Not authenticated or invalid arguments to mod_magic' . EOL; + return $ret; + } + + goaway($dest); + } diff --git a/mod/mail.php b/mod/mail.php new file mode 100644 index 000000000..9c84872ef --- /dev/null +++ b/mod/mail.php @@ -0,0 +1,349 @@ +<?php + +require_once('include/acl_selectors.php'); +require_once('include/message.php'); +require_once('include/zot.php'); +require_once("include/bbcode.php"); +require_once('include/Contact.php'); + + +function mail_post(&$a) { + + if(! local_user()) + return; + + $replyto = ((x($_REQUEST,'replyto')) ? notags(trim($_REQUEST['replyto'])) : ''); + $subject = ((x($_REQUEST,'subject')) ? notags(trim($_REQUEST['subject'])) : ''); + $body = ((x($_REQUEST,'body')) ? escape_tags(trim($_REQUEST['body'])) : ''); + $recipient = ((x($_REQUEST,'messageto')) ? notags(trim($_REQUEST['messageto'])) : ''); + $rstr = ((x($_REQUEST,'messagerecip')) ? notags(trim($_REQUEST['messagerecip'])) : ''); + $expires = ((x($_REQUEST,'expires')) ? datetime_convert(date_default_timezone_get(),'UTC', $_REQUEST['expires']) : '0000-00-00 00:00:00'); + + // If we have a raw string for a recipient which hasn't been auto-filled, + // it means they probably aren't in our address book, hence we don't know + // if we have permission to send them private messages. + // finger them and find out before we try and send it. + + if(! $recipient) { + $channel = $a->get_channel(); + + $ret = zot_finger($rstr,$channel); + + if(! $ret['success']) { + notice( t('Unable to lookup recipient.') . EOL); + return; + } + $j = json_decode($ret['body'],true); + + logger('message_post: lookup: ' . $url . ' ' . print_r($j,true)); + + if(! ($j['success'] && $j['guid'])) { + notice( t('Unable to communicate with requested channel.')); + return; + } + + $x = import_xchan($j); + + if(! $x['success']) { + notice( t('Cannot verify requested channel.')); + return; + } + + $recipient = $x['hash']; + + $their_perms = 0; + + $global_perms = get_perms(); + + if($j['permissions']['data']) { + $permissions = crypto_unencapsulate($j['permissions'],$channel['channel_prvkey']); + if($permissions) + $permissions = json_decode($permissions); + logger('decrypted permissions: ' . print_r($permissions,true), LOGGER_DATA); + } + else + $permissions = $j['permissions']; + + foreach($permissions as $k => $v) { + if($v) { + $their_perms = $their_perms | intval($global_perms[$k][1]); + } + } + + if(! ($their_perms & PERMS_W_MAIL)) { + notice( t('Selected channel has private message restrictions. Send failed.')); + return; + } + } + + if(feature_enabled(local_user(),'richtext')) { + $body = fix_mce_lf($body); + } + + if(! $recipient) { + notice('No recipient found.'); + $a->argc = 2; + $a->argv[1] = 'new'; + return; + } + + // We have a local_user, let send_message use the session channel and save a lookup + + $ret = send_message(0, $recipient, $body, $subject, $replyto, $expires); + + if(! $ret['success']) { + notice($ret['message']); + } + + goaway(z_root() . '/message'); + +} + +function mail_content(&$a) { + + $o = ''; + nav_set_selected('messages'); + + if(! local_user()) { + notice( t('Permission denied.') . EOL); + return login(); + } + + $channel = $a->get_channel(); + head_set_icon($channel['xchan_photo_s']); + + $cipher = get_pconfig(local_user(),'system','default_cipher'); + if(! $cipher) + $cipher = 'aes256'; + + $tpl = get_markup_template('mail_head.tpl'); + $header = replace_macros($tpl, array( + '$messages' => t('Messages'), + '$tab_content' => $tab_content + )); + + if((argc() == 3) && (argv(1) === 'drop')) { + if(! intval(argv(2))) + return; + $cmd = argv(1); + + $r = private_messages_drop(local_user(), argv(2)); + if($r) { + info( t('Message deleted.') . EOL ); + } + goaway($a->get_baseurl(true) . '/message' ); + } + + if((argc() == 3) && (argv(1) === 'recall')) { + if(! intval(argv(2))) + return; + $cmd = argv(1); + $r = q("update mail set mail_flags = mail_flags | %d where id = %d and channel_id = %d limit 1", + intval(MAIL_RECALLED), + intval(argv(2)), + intval(local_user()) + ); + proc_run('php','include/notifier.php','mail',intval(argv(2))); + + if($r) { + info( t('Message recalled.') . EOL ); + } + goaway($a->get_baseurl(true) . '/message' ); + + } + + if((argc() > 1) && (argv(1) === 'new')) { + + $o .= $header; + + $plaintext = false; + if(intval(get_pconfig(local_user(),'system','plaintext'))) + $plaintext = true; + if(! feature_enabled(local_user(),'richtext')) + $plaintext = true; + + $tpl = get_markup_template('msg-header.tpl'); + + $a->page['htmlhead'] .= replace_macros($tpl, array( + '$baseurl' => $a->get_baseurl(true), + '$editselect' => (($plaintext) ? 'none' : '/(profile-jot-text|prvmail-text)/'), + '$nickname' => $channel['channel_address'], + '$linkurl' => t('Please enter a link URL:'), + '$expireswhen' => t('Expires YYYY-MM-DD HH:MM') + )); + + $preselect = (isset($a->argv[2])?array($a->argv[2]):false); + + + $prename = $preurl = $preid = ''; + + if($preselect) { + $r = q("select abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash + where abook_channel = %d and abook_id = %d limit 1", + intval(local_user()), + intval(argv(2)) + ); + if($r) { + $prename = $r[0]['xchan_name']; + $preurl = $r[0]['xchan_url']; + $preid = $r[0]['abook_id']; + } + } + + $prefill = (($preselect) ? $prename : ''); + + if(! $prefill) { + if(array_key_exists('to',$_REQUEST)) + $prefill = $_REQUEST['to']; + } + + // the ugly select box + + $select = contact_select('messageto','message-to-select', $preselect, 4, true, false, false, 10); + + $tpl = get_markup_template('prv_message.tpl'); + $o .= replace_macros($tpl,array( + '$header' => t('Send Private Message'), + '$to' => t('To:'), + '$showinputs' => 'true', + '$prefill' => $prefill, + '$autocomp' => $autocomp, + '$preid' => $preid, + '$subject' => t('Subject:'), + '$subjtxt' => ((x($_REQUEST,'subject')) ? strip_tags($_REQUEST['subject']) : ''), + '$text' => ((x($_REQUEST,'body')) ? htmlspecialchars($_REQUEST['body'], ENT_COMPAT, 'UTF-8') : ''), + '$readonly' => '', + '$yourmessage' => t('Your message:'), + '$select' => $select, + '$parent' => '', + '$upload' => t('Upload photo'), + '$attach' => t('Attach file'), + '$insert' => t('Insert web link'), + '$wait' => t('Please wait'), + '$submit' => t('Submit'), + '$defexpire' => '', + '$feature_expire' => ((feature_enabled(local_user(),'content_expire')) ? true : false), + '$expires' => t('Set expiration date'), + '$feature_encrypt' => ((feature_enabled(local_user(),'content_encrypt')) ? true : false), + '$encrypt' => t('Encrypt text'), + '$cipher' => $cipher, + + + )); + + return $o; + } + + + if((argc() > 1) && (intval(argv(1)))) { + + $o .= $header; + + $plaintext = true; + if( local_user() && feature_enabled(local_user(),'richtext') ) + $plaintext = false; + + $messages = private_messages_fetch_conversation(local_user(), argv(1), true); + + if(! $messages) { + info( t('Message not found.') . EOL); + return $o; + } + + if($messages[0]['to_xchan'] === $channel['channel_hash']) + $a->poi = $messages[0]['from']; + else + $a->poi = $messages[0]['to']; + +// require_once('include/Contact.php'); + +// $a->set_widget('mail_conversant',vcard_from_xchan($a->poi,$get_observer_hash,'mail')); + + + $tpl = get_markup_template('msg-header.tpl'); + + $a->page['htmlhead'] .= replace_macros($tpl, array( + '$nickname' => $channel['channel_addr'], + '$baseurl' => $a->get_baseurl(true), + '$editselect' => (($plaintext) ? 'none' : '/(profile-jot-text|prvmail-text)/'), + '$linkurl' => t('Please enter a link URL:'), + '$expireswhen' => t('Expires YYYY-MM-DD HH:MM') + )); + + + $mails = array(); + $seen = 0; + $unknown = false; + + foreach($messages as $message) { + + $s = theme_attachments($message); + + $mails[] = array( + 'id' => $message['id'], + 'from_name' => $message['from']['xchan_name'], + 'from_url' => chanlink_hash($message['from_xchan']), + 'from_photo' => $message['from']['xchan_photo_m'], + 'to_name' => $message['to']['xchan_name'], + 'to_url' => chanlink_hash($message['to_xchan']), + 'to_photo' => $message['to']['xchan_photo_m'], + 'subject' => $message['title'], + 'body' => smilies(bbcode($message['body']) . $s), + 'delete' => t('Delete message'), + 'recall' => t('Recall message'), + 'can_recall' => (($channel['channel_hash'] == $message['from_xchan']) ? true : false), + 'is_recalled' => (($message['mail_flags'] & MAIL_RECALLED) ? t('Message has been recalled.') : ''), + 'date' => datetime_convert('UTC',date_default_timezone_get(),$message['created'],'D, d M Y - g:i A'), + ); + + $seen = $message['seen']; + + } + + $recp = (($message['from_xchan'] === $channel['channel_hash']) ? 'to' : 'from'); + +// FIXME - move this HTML to template + + $select = $message[$recp]['xchan_name'] . '<input type="hidden" name="messageto" value="' . $message[$recp]['xchan_hash'] . '" />'; + $parent = '<input type="hidden" name="replyto" value="' . $message['parent_mid'] . '" />'; + + $tpl = get_markup_template('mail_display.tpl'); + $o = replace_macros($tpl, array( + '$prvmsg_header' => t('Private Conversation'), + '$thread_id' => $a->argv[1], + '$thread_subject' => $message['title'], + '$thread_seen' => $seen, + '$delete' => t('Delete conversation'), + '$canreply' => (($unknown) ? false : '1'), + '$unknown_text' => t("No secure communications available. You <strong>may</strong> be able to respond from the sender's profile page."), + '$mails' => $mails, + + // reply + '$header' => t('Send Reply'), + '$to' => t('To:'), + '$showinputs' => '', + '$subject' => t('Subject:'), + '$subjtxt' => $message['title'], + '$readonly' => ' readonly="readonly" style="background: #BBBBBB;" ', + '$yourmessage' => t('Your message:'), + '$text' => '', + '$select' => $select, + '$parent' => $parent, + '$upload' => t('Upload photo'), + '$attach' => t('Attach file'), + '$insert' => t('Insert web link'), + '$submit' => t('Submit'), + '$wait' => t('Please wait'), + '$defexpire' => '', + '$feature_expire' => ((feature_enabled(local_user(),'content_expire')) ? true : false), + '$expires' => t('Set expiration date'), + '$feature_encrypt' => ((feature_enabled(local_user(),'content_encrypt')) ? true : false), + '$encrypt' => t('Encrypt text'), + '$cipher' => $cipher, + + )); + + return $o; + } + +} diff --git a/mod/manage.php b/mod/manage.php index 2cdfce115..0772e2d61 100644 --- a/mod/manage.php +++ b/mod/manage.php @@ -36,8 +36,9 @@ function manage_content(&$a) { $channels = null; if(local_user()) { - $r = q("select channel.*, xchan.* from channel left join xchan on channel.channel_hash = xchan.xchan_hash where channel.channel_account_id = %d order by channel_name ", - intval(get_account_id()) + $r = q("select channel.*, xchan.* from channel left join xchan on channel.channel_hash = xchan.xchan_hash where channel.channel_account_id = %d and not ( channel_pageflags & %d ) order by channel_name ", + intval(get_account_id()), + intval(PAGE_REMOVED) ); $selected_channel = null; @@ -53,6 +54,18 @@ function manage_content(&$a) { $channels[$x]['default_links'] = '1'; } } + + $r = q("select count(channel_id) as total from channel where channel_account_id = %d and not ( channel_pageflags & %d )", + intval(get_account_id()), + intval(PAGE_REMOVED) + ); + $limit = service_class_fetch(local_user(),'total_identities'); + if($limit !== false) { + $channel_usage_message = sprintf( t("You have created %1$.0f of %2$.0f allowed channels."), $r[0]['total'], $limit); + } + else { + $channel_usage_message = ''; + } } $links = array( @@ -69,6 +82,7 @@ function manage_content(&$a) { '$msg_make_default' => t('Make Default'), '$links' => $links, '$all_channels' => $channels, + '$channel_usage_message' => $channel_usage_message, )); diff --git a/mod/match.php b/mod/match.php index 23eeb9370..5447f755d 100644 --- a/mod/match.php +++ b/mod/match.php @@ -1,5 +1,9 @@ <?php +// FIXME - this has never been properly ported from Friendica +// It takes keywords from your profile and queries the directory server for +// matching keywords from other profiles. + function match_content(&$a) { @@ -30,10 +34,10 @@ function match_content(&$a) { if($a->pager['page'] != 1) $params['p'] = $a->pager['page']; - if(strlen(get_config('system','directory_submit_url'))) - $x = post_url('http://dir.friendica.com/msearch', $params); - else - $x = post_url($a->get_baseurl() . '/msearch', $params); +// if(strlen(get_config('system','directory_submit_url'))) +// $x = post_url('http://dir.friendica.com/msearch', $params); +// else +// $x = post_url($a->get_baseurl() . '/msearch', $params); $j = json_decode($x); diff --git a/mod/menu.php b/mod/menu.php new file mode 100644 index 000000000..a2d0c2385 --- /dev/null +++ b/mod/menu.php @@ -0,0 +1,125 @@ +<?php + +require_once('include/menu.php'); + +function menu_post(&$a) { + + if(! local_user()) + return; + + $_REQUEST['menu_channel_id'] = local_user(); + if($_REQUEST['menu_bookmark']) + $_REQUEST['menu_flags'] |= MENU_BOOKMARK; + if($_REQUEST['menu_system']) + $_REQUEST['menu_flags'] |= MENU_SYSTEM; + + $menu_id = ((argc() > 1) ? intval(argv(1)) : 0); + if($menu_id) { + $_REQUEST['menu_id'] = intval(argv(1)); + $r = menu_edit($_REQUEST); + if($r) { + info( t('Menu updated.') . EOL); + goaway(z_root() . '/mitem/' . $menu_id); + } + else + notice( t('Unable to update menu.'). EOL); + } + else { + $r = menu_create($_REQUEST); + if($r) { + info( t('Menu created.') . EOL); + goaway(z_root() . '/mitem/' . $r); + } + else + notice( t('Unable to create menu.'). EOL); + + } + +} + + +function menu_content(&$a) { + + if(! local_user()) { + notice( t('Permission denied.') . EOL); + return ''; + } + + +// $a->set_widget('design',design_tools()); + + + if(argc() == 1) { + // list menus + $x = menu_list(local_user()); + + $o = replace_macros(get_markup_template('menulist.tpl'),array( + '$title' => t('Manage Menus'), + '$menus' => $x, + '$edit' => t('Edit'), + '$drop' => t('Drop'), + '$new' => t('New'), + '$hintnew' => t('Create a new menu'), + '$hintdrop' => t('Delete this menu'), + '$hintcontent' => t('Edit menu contents'), + '$hintedit' => t('Edit this menu') + )); + + return $o; + + + + + + } + + + if(argc() > 1) { + if(argv(1) === 'new') { + $o = replace_macros(get_markup_template('menuedit.tpl'), array( + '$header' => t('New Menu'), + '$menu_name' => array('menu_name', t('Menu name'), '', t('Must be unique, only seen by you'), '*'), + '$menu_desc' => array('menu_desc', t('Menu title'), '', t('Menu title as seen by others'), ''), + '$menu_bookmark' => array('menu_bookmark', t('Allow bookmarks'), 0 , t('Menu may be used to store saved bookmarks'), ''), + '$submit' => t('Create') + )); + return $o; + } + + elseif(intval(argv(1))) { + $m = menu_fetch_id(intval(argv(1)),local_user()); + if(! $m) { + notice( t('Menu not found.') . EOL); + return ''; + } + if(argc() == 3 && argv(2) == 'drop') { + $r = menu_delete_id(intval(argv(1)),local_user()); + if($r) + info( t('Menu deleted.') . EOL); + else + notice( t('Menu could not be deleted.'). EOL); + + goaway(z_root() . '/menu'); + } + else { + $o = replace_macros(get_markup_template('menuedit.tpl'), array( + '$header' => t('Edit Menu'), + '$menu_id' => intval(argv(1)), + '$hintedit' => t('Add or remove entries to this menu'), + '$editcontents' => t('Edit menu contents'), + '$menu_name' => array('menu_name', t('Menu name'), $m['menu_name'], t('Must be unique, only seen by you'), '*'), + '$menu_desc' => array('menu_desc', t('Menu title'), $m['menu_desc'], t('Menu title as seen by others'), ''), + '$menu_bookmark' => array('menu_bookmark', t('Allow bookmarks'), (($m['menu_flags'] & MENU_BOOKMARK) ? 1 : 0), t('Menu may be used to store saved bookmarks'), ''), + '$menu_system' => (($m['menu_flags'] & MENU_SYSTEM) ? 1 : 0), + '$submit' => t('Modify') + )); + return $o; + } + } + else { + notice( t('Not found.') . EOL); + return; + } + } + +} diff --git a/mod/message.php b/mod/message.php index e3a67b23e..c14bf2161 100644 --- a/mod/message.php +++ b/mod/message.php @@ -3,218 +3,8 @@ require_once('include/acl_selectors.php'); require_once('include/message.php'); require_once('include/zot.php'); - -function message_init(&$a) { - $tabs = array(); - $new = array( - 'label' => t('New Message'), - 'url' => $a->get_baseurl(true) . '/message/new', - 'sel'=> (argv(1) == 'new'), - ); - - $tpl = get_markup_template('message_side.tpl'); - $a->page['aside'] = replace_macros($tpl, array( - '$tabs'=>$tabs, - '$new'=>$new, - )); - $base = $a->get_baseurl(); - - $a->page['htmlhead'] .= <<< EOT - -<script>$(document).ready(function() { - var a; - a = $("#recip").autocomplete({ - serviceUrl: '$base/acl', - minChars: 2, - width: 350, - onSelect: function(value,data) { - $("#recip-complete").val(data); - } - }); - -}); - -</script> -EOT; - -} - -function message_post(&$a) { - - if(! local_user()) { - notice( t('Permission denied.') . EOL); - return; - } - - $replyto = ((x($_REQUEST,'replyto')) ? notags(trim($_REQUEST['replyto'])) : ''); - $subject = ((x($_REQUEST,'subject')) ? notags(trim($_REQUEST['subject'])) : ''); - $body = ((x($_REQUEST,'body')) ? escape_tags(trim($_REQUEST['body'])) : ''); - $recipient = ((x($_REQUEST,'messageto')) ? notags(trim($_REQUEST['messageto'])) : ''); - $rstr = ((x($_REQUEST,'messagerecip')) ? notags(trim($_REQUEST['messagerecip'])) : ''); - - if(! $recipient) { - $channel = $a->get_channel(); - - $ret = zot_finger($rstr,$channel); - - if(! $ret) { - notice( t('Unable to lookup recipient.') . EOL); - return; - } - $j = json_decode($ret['body'],true); - - logger('message_post: lookup: ' . $url . ' ' . print_r($j,true)); - - if(! ($j['success'] && $j['guid'])) { - notice( t('Unable to communicate with requested channel.')); - return; - } - - $x = import_xchan($j); - - if(! $x['success']) { - notice( t('Cannot verify requested channel.')); - return; - } - - $recipient = $x['hash']; - - $their_perms = 0; - - $global_perms = get_perms(); - - if($j['permissions']['data']) { - $permissions = aes_unencapsulate($j['permissions'],$channel['channel_prvkey']); - if($permissions) - $permissions = json_decode($permissions); - logger('decrypted permissions: ' . print_r($permissions,true), LOGGER_DATA); - } - else - $permissions = $j['permissions']; - - foreach($permissions as $k => $v) { - if($v) { - $their_perms = $their_perms | intval($global_perms[$k][1]); - } - } - - if(! ($their_perms & PERMS_W_MAIL)) { - notice( t('Selected channel has private message restrictions. Send failed.')); - return; - } - } - - - if(feature_enabled(local_user(),'richtext')) { - $body = fix_mce_lf($body); - } - - $ret = send_message(local_user(), $recipient, $body, $subject, $replyto); - $norecip = false; - - switch($ret){ - case -1: - notice( t('No recipient selected.') . EOL ); - $norecip = true; - break; - case -2: - notice( t('Unable to locate contact information.') . EOL ); - break; - case -3: - notice( t('Message could not be sent.') . EOL ); - break; - case -4: - notice( t('Message collection failure.') . EOL ); - break; - default: - info( t('Message sent.') . EOL ); - } - - // fake it to go back to the input form if no recipient listed - - if($norecip) { - $a->argc = 2; - $a->argv[1] = 'new'; - } - -} - -// Note: the code in 'item_extract_images' and 'item_redir_and_replace_images' -// is identical to the code in include/conversation.php -if(! function_exists('item_extract_images')) { -function item_extract_images($body) { - - $saved_image = array(); - $orig_body = $body; - $new_body = ''; - - $cnt = 0; - $img_start = strpos($orig_body, '[img'); - $img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false); - $img_end = ($img_start !== false ? strpos(substr($orig_body, $img_start), '[/img]') : false); - while(($img_st_close !== false) && ($img_end !== false)) { - - $img_st_close++; // make it point to AFTER the closing bracket - $img_end += $img_start; - - if(! strcmp(substr($orig_body, $img_start + $img_st_close, 5), 'data:')) { - // This is an embedded image - - $saved_image[$cnt] = substr($orig_body, $img_start + $img_st_close, $img_end - ($img_start + $img_st_close)); - $new_body = $new_body . substr($orig_body, 0, $img_start) . '[!#saved_image' . $cnt . '#!]'; - - $cnt++; - } - else - $new_body = $new_body . substr($orig_body, 0, $img_end + strlen('[/img]')); - - $orig_body = substr($orig_body, $img_end + strlen('[/img]')); - - if($orig_body === false) // in case the body ends on a closing image tag - $orig_body = ''; - - $img_start = strpos($orig_body, '[img'); - $img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false); - $img_end = ($img_start !== false ? strpos(substr($orig_body, $img_start), '[/img]') : false); - } - - $new_body = $new_body . $orig_body; - - return array('body' => $new_body, 'images' => $saved_image); -}} - -if(! function_exists('item_redir_and_replace_images')) { -function item_redir_and_replace_images($body, $images, $cid) { - - $origbody = $body; - $newbody = ''; - - for($i = 0; $i < count($images); $i++) { - $search = '/\[url\=(.*?)\]\[!#saved_image' . $i . '#!\]\[\/url\]' . '/is'; - $replace = '[url=' . z_path() . '/redir/' . $cid - . '?f=1&url=' . '$1' . '][!#saved_image' . $i . '#!][/url]' ; - - $img_end = strpos($origbody, '[!#saved_image' . $i . '#!][/url]') + strlen('[!#saved_image' . $i . '#!][/url]'); - $process_part = substr($origbody, 0, $img_end); - $origbody = substr($origbody, $img_end); - - $process_part = preg_replace($search, $replace, $process_part); - $newbody = $newbody . $process_part; - } - $newbody = $newbody . $origbody; - - $cnt = 0; - foreach($images as $image) { - // We're depending on the property of 'foreach' (specified on the PHP website) that - // it loops over the array starting from the first element and going sequentially - // to the last element - $newbody = str_replace('[!#saved_image' . $cnt . '#!]', '[img]' . $image . '[/img]', $newbody); - $cnt++; - } - - return $newbody; -}} - +require_once("include/bbcode.php"); +require_once('include/Contact.php'); function message_content(&$a) { @@ -224,10 +14,17 @@ function message_content(&$a) { if(! local_user()) { notice( t('Permission denied.') . EOL); - return; + return login(); } - $myprofile = $a->get_baseurl(true) . '/channel/' . $a->user['nickname']; + $channel = $a->get_channel(); + head_set_icon($channel['xchan_photo_s']); + + $cipher = get_pconfig(local_user(),'system','default_cipher'); + if(! $cipher) + $cipher = 'aes256'; + + $tpl = get_markup_template('mail_head.tpl'); $header = replace_macros($tpl, array( @@ -235,297 +32,52 @@ function message_content(&$a) { '$tab_content' => $tab_content )); - - if((argc() == 3) && (argv(1) === 'drop' || argv(1) === 'dropconv')) { + if((argc() == 3) && (argv(1) === 'dropconv')) { if(! intval(argv(2))) return; $cmd = argv(1); - if($cmd === 'drop') { - $r = q("DELETE FROM `mail` WHERE `id` = %d AND channel_id = %d LIMIT 1", - intval(argv(2)), - intval(local_user()) - ); - if($r) { - info( t('Message deleted.') . EOL ); - } - goaway($a->get_baseurl(true) . '/message' ); - } - else { - $r = q("SELECT `parent_uri` FROM `mail` WHERE `id` = %d AND channel_id = %d LIMIT 1", - intval(argv(2)), - intval(local_user()) - ); - if(count($r)) { - $parent = $r[0]['parent_uri']; - - - $r = q("DELETE FROM `mail` WHERE `parent_uri` = '%s' AND channel_id = %d ", - dbesc($parent), - intval(local_user()) - ); - - if($r) - info( t('Conversation removed.') . EOL ); - } - goaway($a->get_baseurl(true) . '/message' ); - } - - } - - $channel = $a->get_channel(); - - if((argc() > 1) && ($a->argv[1] === 'new')) { - - $o .= $header; - - $plaintext = false; - if(intval(get_pconfig(local_user(),'system','plaintext'))) - $plaintext = true; - if(! feature_enabled(local_user(),'richtext')) - $plaintext = true; - - $tpl = get_markup_template('msg-header.tpl'); - - $a->page['htmlhead'] .= replace_macros($tpl, array( - '$baseurl' => $a->get_baseurl(true), - '$editselect' => (($plaintext) ? 'none' : '/(profile-jot-text|prvmail-text)/'), - '$nickname' => $channel['channel_addr'], - '$linkurl' => t('Please enter a link URL:') - )); - - $preselect = (isset($a->argv[2])?array($a->argv[2]):false); - - - $prename = $preurl = $preid = ''; - - if($preselect) { - $r = q("select abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash - where abook_channel = %d and abook_id = %d limit 1", - intval(local_user()), - intval(argv(2)) - ); - if($r) { - $prename = $r[0]['xchan_name']; - $preurl = $r[0]['xchan_url']; - $preid = $r[0]['abook_id']; - } - } - - $prefill = (($preselect) ? $prename : ''); - - // the ugly select box - - $select = contact_select('messageto','message-to-select', $preselect, 4, true, false, false, 10); - - $tpl = get_markup_template('prv_message.tpl'); - $o .= replace_macros($tpl,array( - '$header' => t('Send Private Message'), - '$to' => t('To:'), - '$showinputs' => 'true', - '$prefill' => $prefill, - '$autocomp' => $autocomp, - '$preid' => $preid, - '$subject' => t('Subject:'), - '$subjtxt' => ((x($_REQUEST,'subject')) ? strip_tags($_REQUEST['subject']) : ''), - '$text' => ((x($_REQUEST,'body')) ? escape_tags(htmlspecialchars($_REQUEST['body'])) : ''), - '$readonly' => '', - '$yourmessage' => t('Your message:'), - '$select' => $select, - '$parent' => '', - '$upload' => t('Upload photo'), - '$insert' => t('Insert web link'), - '$wait' => t('Please wait'), - '$submit' => t('Submit') - )); - - return $o; + $r = private_messages_drop(local_user(), argv(2), true); + if($r) + info( t('Conversation removed.') . EOL ); + goaway($a->get_baseurl(true) . '/message' ); } - if(argc() == 1) { // list messages $o .= $header; - - $r = q("SELECT count(*) AS `total` FROM `mail` - WHERE channel_id = %d", - intval(local_user()) - ); - if($r) - $a->set_pager_total($r[0]['total']); + // private_messages_list() can do other more complicated stuff, for now keep it simple + + + $r = private_messages_list(local_user(), '', $a->pager['start'], $a->pager['itemspage']); - $r = q("SELECT * from mail WHERE channel_id = %d order by created desc limit %d, %d", - intval(local_user()), - intval($a->pager['start']), - intval($a->pager['itemspage']) - ); if(! $r) { info( t('No messages.') . EOL); return $o; } - $chans = array(); - foreach($r as $rr) { - $s = "'" . dbesc(trim($rr['from_xchan'])) . "'"; - if(! in_array($s,$chans)) - $chans[] = $s; - $s = "'" . dbesc(trim($rr['to_xchan'])) . "'"; - if(! in_array($s,$chans)) - $chans[] = $s; - } - - $c = q("select * from xchan where xchan_hash in (" . implode(',',$chans) . ")"); - $tpl = get_markup_template('mail_list.tpl'); foreach($r as $rr) { - $rr['from'] = find_xchan_in_array($rr['from_xchan'],$c); - $rr['to'] = find_xchan_in_array($rr['to_xchan'],$c); - $rr['seen'] = (($rr['mail_flags'] & MAIL_SEEN) ? 1 : ""); - + $o .= replace_macros($tpl, array( '$id' => $rr['id'], - '$from_name' => template_escape($rr['from']['xchan_name']), - '$from_url' => z_root() . '/chanview/?f=&hash=' . $rr['from_xchan'], + '$from_name' => $rr['from']['xchan_name'], + '$from_url' => chanlink_hash($rr['from_xchan']), '$from_photo' => $rr['from']['xchan_photo_s'], - '$to_name' => template_escape($rr['to']['xchan_name']), - '$to_url' => z_root() . '/chanview/?f=&hash=' . $rr['to_xchan'], + '$to_name' => $rr['to']['xchan_name'], + '$to_url' => chanlink_hash($rr['to_xchan']), '$to_photo' => $rr['to']['xchan_photo_s'], - '$subject' => template_escape((($rr['seen']) ? $rr['title'] : '<strong>' . $rr['title'] . '</strong>')), + '$subject' => (($rr['seen']) ? $rr['title'] : '<strong>' . $rr['title'] . '</strong>'), '$delete' => t('Delete message'), - '$body' => template_escape($rr['body']), + '$body' => smilies(bbcode($rr['body'])), '$date' => datetime_convert('UTC',date_default_timezone_get(),$rr['created'], t('D, d M Y - g:i A')), '$seen' => $rr['seen'] )); } - $o .= paginate($a); + $o .= alt_pager($a,count($r)); return $o; } - if((argc() > 1) && (intval(argv(1)))) { - - $o .= $header; - - $r = q("SELECT parent_uri from mail WHERE channel_id = %d and id = %d limit 1", - intval(local_user()), - intval(argv(1)) - ); - - if(! $r) { - info( t('Message not found.') . EOL); - return $o; - } - - $messages = q("select * from mail where parent_uri = '%s' and channel_id = %d order by created asc", - dbesc($r[0]['parent_uri']), - intval(local_user()) - ); - - if(! $messages) { - info( t('Message not found.') . EOL); - return $o; - } - - $chans = array(); - foreach($messages as $rr) { - $s = "'" . dbesc(trim($rr['from_xchan'])) . "'"; - if(! in_array($s,$chans)) - $chans[] = $s; - $s = "'" . dbesc(trim($rr['to_xchan'])) . "'"; - if(! in_array($s,$chans)) - $chans[] = $s; - } - - -dbg(1); - $c = q("select * from xchan where xchan_hash in (" . implode(',',$chans) . ")"); - - $r = q("UPDATE `mail` SET mail_flags = (mail_flags ^ %d) where not (mail_flags & %d) and parent_uri = '%s' AND channel_id = %d", - intval(MAIL_SEEN), - intval(MAIL_SEEN), - dbesc($r[0]['parent_uri']), - intval(local_user()) - ); -dbg(0); - require_once("include/bbcode.php"); - - $tpl = get_markup_template('msg-header.tpl'); - - $a->page['htmlhead'] .= replace_macros($tpl, array( - '$nickname' => $channel['channel_addr'], - '$baseurl' => $a->get_baseurl(true) - )); - - - $mails = array(); - $seen = 0; - $unknown = false; - - foreach($messages as $message) { - $message['from'] = find_xchan_in_array($message['from_xchan'],$c); - $message['to'] = find_xchan_in_array($message['to_xchan'],$c); - - -logger('message: ' . print_r($message,true)); - -// $extracted = item_extract_images($message['body']); -// if($extracted['images']) -// $message['body'] = item_redir_and_replace_images($extracted['body'], $extracted['images'], $message['contact-id']); - - $mails[] = array( - 'id' => $message['id'], - 'from_name' => template_escape($message['from']['xchan_name']), - 'from_url' => z_root() . '/chanview/?f=&hash=' . $message['from_xchan'], - 'from_photo' => $message['from']['xchan_photo_m'], - 'to_name' => template_escape($message['to']['xchan_name']), - 'to_url' => z_root() . '/chanview/?f=&hash=' . $message['to_xchan'], - 'to_photo' => $message['to']['xchan_photo_m'], - 'subject' => template_escape($message['title']), - 'body' => template_escape(smilies(bbcode($message['body']))), - 'delete' => t('Delete message'), - 'date' => datetime_convert('UTC',date_default_timezone_get(),$message['created'],'D, d M Y - g:i A'), - ); - - $seen = $message['seen']; - - } - - logger('mails: ' . print_r($mails,true)); - - $recp = (($message['from_xchan'] === $channel['channel_hash']) ? 'to' : 'from'); - - $select = $message[$recp]['xchan_name'] . '<input type="hidden" name="messageto" value="' . $message[$recp]['xchan_hash'] . '" />'; - $parent = '<input type="hidden" name="replyto" value="' . $message['parent_uri'] . '" />'; - - $tpl = get_markup_template('mail_display.tpl'); - $o = replace_macros($tpl, array( - '$thread_id' => $a->argv[1], - '$thread_subject' => $message['title'], - '$thread_seen' => $seen, - '$delete' => t('Delete conversation'), - '$canreply' => (($unknown) ? false : '1'), - '$unknown_text' => t("No secure communications available. You <strong>may</strong> be able to respond from the sender's profile page."), - '$mails' => $mails, - - // reply - '$header' => t('Send Reply'), - '$to' => t('To:'), - '$showinputs' => '', - '$subject' => t('Subject:'), - '$subjtxt' => template_escape($message['title']), - '$readonly' => ' readonly="readonly" style="background: #BBBBBB;" ', - '$yourmessage' => t('Your message:'), - '$text' => '', - '$select' => $select, - '$parent' => $parent, - '$upload' => t('Upload photo'), - '$insert' => t('Insert web link'), - '$submit' => t('Submit'), - '$wait' => t('Please wait') - - )); - - return $o; - } } diff --git a/mod/mitem.php b/mod/mitem.php new file mode 100644 index 000000000..3240bb68b --- /dev/null +++ b/mod/mitem.php @@ -0,0 +1,197 @@ +<?php + +require_once('include/menu.php'); +require_once('include/acl_selectors.php'); + +function mitem_init(&$a) { + if(! local_user()) + return; + if(argc() < 2) + return; + + $m = menu_fetch_id(intval(argv(1)),local_user()); + if(! $m) { + notice( t('Menu not found.') . EOL); + return ''; + } + $a->data['menu'] = $m; + +} + +function mitem_post(&$a) { + + if(! local_user()) + return; + + if(! $a->data['menu']) + return; + + + $channel = $a->get_channel(); + + $_REQUEST['mitem_channel_id'] = local_user(); + $_REQUEST['menu_id'] = $a->data['menu']['menu_id']; + + $_REQUEST['mitem_flags'] = 0; + if($_REQUEST['usezid']) + $_REQUEST['mitem_flags'] |= MENU_ITEM_ZID; + if($_REQUEST['newwin']) + $_REQUEST['mitem_flags'] |= MENU_ITEM_NEWWIN; + + + $mitem_id = ((argc() > 2) ? intval(argv(2)) : 0); + if($mitem_id) { + $_REQUEST['mitem_id'] = $mitem_id; + $r = menu_edit_item($_REQUEST['menu_id'],local_user(),$_REQUEST); + if($r) { + info( t('Menu element updated.') . EOL); + goaway(z_root() . '/mitem/' . $_REQUEST['menu_id']); + } + else + notice( t('Unable to update menu element.') . EOL); + + } + else { + $r = menu_add_item($_REQUEST['menu_id'],local_user(),$_REQUEST); + if($r) { + info( t('Menu element added.') . EOL); + goaway(z_root() . '/mitem/' . $_REQUEST['menu_id']); + } + else + notice( t('Unable to add menu element.') . EOL); + + } + + + +} + + +function mitem_content(&$a) { + + if(! local_user()) { + notice( t('Permission denied.') . EOL); + return ''; + } + + if(argc() < 2 || (! $a->data['menu'])) { + notice( t('Not found.') . EOL); + return ''; + } + + $channel = $a->get_channel(); + + $m = menu_fetch($a->data['menu']['menu_name'],local_user(), get_observer_hash()); + $a->data['menu_item'] = $m; + + + if(argc() == 2) { + $r = q("select * from menu_item where mitem_menu_id = %d and mitem_channel_id = %d order by mitem_order asc, mitem_desc asc", + intval($a->data['menu']['menu_id']), + local_user() + ); + + + $o .= replace_macros(get_markup_template('mitemlist.tpl'),array( + '$title' => t('Manage Menu Elements'), + '$menuname' => $a->data['menu']['menu_name'], + '$menudesc' => $a->data['menu']['menu_desc'], + '$edmenu' => t('Edit menu'), + '$menu_id' => $a->data['menu']['menu_id'], + '$mlist' => $r, + '$edit' => t('Edit element'), + '$drop' => t('Drop element'), + '$new' => t('New element'), + '$hintmenu' => t('Edit this menu container'), + '$hintnew' => t('Add menu element'), + '$hintdrop' => t('Delete this menu item'), + '$hintedit' => t('Edit this menu item') + )); + + + return $o; + + } + + + if(argc() > 2) { + + + + if(argv(2) === 'new') { + + $perm_defaults = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + + $o = replace_macros(get_markup_template('mitemedit.tpl'), array( + '$header' => t('New Menu Element'), + '$menu_id' => $a->data['menu']['menu_id'], + '$permissions' => t('Menu Item Permissions'), + '$permdesc' => t("\x28click to open/close\x29"), + '$aclselect' => populate_acl($perm_defaults,false), + '$mitem_desc' => array('mitem_desc', t('Link text'), '', '','*'), + '$mitem_link' => array('mitem_link', t('URL of link'), '', '', '*'), + '$usezid' => array('usezid', t('Use Red magic-auth if available'), true, ''), + '$newwin' => array('newwin', t('Open link in new window'), false,''), +// permissions go here + '$mitem_order' => array('mitem_order', t('Order in list'),'0',t('Higher numbers will sink to bottom of listing')), + '$submit' => t('Create') + )); + return $o; + } + + + elseif(intval(argv(2))) { + $m = q("select * from menu_item where mitem_id = %d and mitem_channel_id = %d limit 1", + intval(argv(2)), + intval(local_user()) + ); + if(! $m) { + notice( t('Menu item not found.') . EOL); + goaway(z_root() . '/menu'); + } + + $mitem = $m[0]; + + if(argc() == 4 && argv(3) == 'drop') { + $r = menu_del_item($mitem['mitem_menu_id'], local_user(),intval(argv(2))); + if($r) + info( t('Menu item deleted.') . EOL); + else + notice( t('Menu item could not be deleted.'). EOL); + + goaway(z_root() . '/mitem/' . $mitem['mitem_menu_id']); + } + else { + + // edit menu item + + $o = replace_macros(get_markup_template('mitemedit.tpl'), array( + '$header' => t('Edit Menu Element'), + '$menu_id' => $a->data['menu']['menu_id'], + '$permissions' => t('Menu Item Permissions'), + '$permdesc' => t("\x28click to open/close\x29"), + '$aclselect' => populate_acl($mitem,false), + '$mitem_id' => intval(argv(2)), + '$mitem_desc' => array('mitem_desc', t('Link text'), $mitem['mitem_desc'], '','*'), + '$mitem_link' => array('mitem_link', t('URL of link'), $mitem['mitem_link'], '', '*'), + '$usezid' => array('usezid', t('Use Red magic-auth if available'), (($mitem['mitem_flags'] & MENU_ITEM_ZID) ? 1 : 0), ''), + '$newwin' => array('newwin', t('Open link in new window'), (($mitem['mitem_flags'] & MENU_ITEM_NEWWIN) ? 1 : 0),''), +// permissions go here + '$mitem_order' => array('mitem_order', t('Order in list'),$mitem['mitem_order'],t('Higher numbers will sink to bottom of listing')), + '$submit' => t('Modify') + )); + return $o; + } + } + + } + + + + +} diff --git a/mod/mood.php b/mod/mood.php index 98064beab..ff765fcac 100755 --- a/mod/mood.php +++ b/mod/mood.php @@ -11,6 +11,7 @@ function mood_init(&$a) { return; $uid = local_user(); + $channel = $a->get_channel(); $verb = notags(trim($_GET['verb'])); if(! $verb) @@ -18,7 +19,7 @@ function mood_init(&$a) { $verbs = get_mood_verbs(); - if(! in_array($verb,$verbs)) + if(! array_key_exists($verb,$verbs)) return; $activity = ACTIVITY_MOOD . '#' . urlencode($verb); @@ -30,15 +31,15 @@ function mood_init(&$a) { if($parent) { - $r = q("select uri, owner_xchan, private, allow_cid, allow_gid, deny_cid, deny_gid + $r = q("select mid, owner_xchan, private, allow_cid, allow_gid, deny_cid, deny_gid from item where id = %d and parent = %d and uid = %d limit 1", intval($parent), intval($parent), intval($uid) ); if(count($r)) { - $parent_uri = $r[0]['uri']; - $private = $r[0]['private']; + $parent_mid = $r[0]['mid']; + $private = $r[0]['item_private']; $allow_cid = $r[0]['allow_cid']; $allow_gid = $r[0]['allow_gid']; $deny_cid = $r[0]['deny_cid']; @@ -48,7 +49,6 @@ function mood_init(&$a) { else { $private = 0; - $channel = $a->get_channel(); $allow_cid = $channel['channel_allow_cid']; $allow_gid = $channel['channel_allow_gid']; @@ -58,11 +58,11 @@ function mood_init(&$a) { $poster = $a->get_observer(); - $uri = item_message_id(); + $mid = item_message_id(); - $action = sprintf( t('%1$s is currently %2$s'), '[url=' . $poster['xchan_url'] . ']' . $poster['xchan_name'] . '[/url]' , $verbs[$verb]); + $action = sprintf( t('%1$s is %2$s','mood'), '[zrl=' . $poster['xchan_url'] . ']' . $poster['xchan_name'] . '[/zrl]' , $verbs[$verb]); $item_flags = ITEM_WALL|ITEM_ORIGIN|ITEM_UNSEEN; - if(! $parent_uri) + if(! $parent_mid) $item_flags |= ITEM_THREAD_TOP; @@ -70,29 +70,30 @@ function mood_init(&$a) { $arr['aid'] = get_account_id(); $arr['uid'] = $uid; - $arr['uri'] = $uri; - $arr['parent_uri'] = (($parent_uri) ? $parent_uri : $uri); + $arr['mid'] = $mid; + $arr['parent_mid'] = (($parent_mid) ? $parent_mid : $mid); $arr['item_flags'] = $item_flags; $arr['author_xchan'] = $poster['xchan_hash']; - $arr['owner_xchan'] = (($parent_uri) ? $r[0]['owner_xchan'] : $poster['xchan_hash']); + $arr['owner_xchan'] = (($parent_mid) ? $r[0]['owner_xchan'] : $poster['xchan_hash']); $arr['title'] = ''; $arr['allow_cid'] = $allow_cid; $arr['allow_gid'] = $allow_gid; $arr['deny_cid'] = $deny_cid; $arr['deny_gid'] = $deny_gid; + $arr['item_private'] = $private; $arr['verb'] = $activity; $arr['body'] = $action; - $item_id = item_store($arr); - if($item_id) { -// q("UPDATE `item` SET `plink` = '%s' WHERE `uid` = %d AND `id` = %d LIMIT 1", -// dbesc($a->get_baseurl() . '/display/' . $poster['nickname'] . '/' . $item_id), -// intval($uid), -// intval($item_id) -// ); + if ((! $arr['plink']) && ($arr['item_flags'] & ITEM_THREAD_TOP)) { + $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid']; + } - proc_run('php',"include/notifier.php","activity", $item_id); + $post = item_store($arr); + $item_id = $post['item_id']; + + if($item_id) { + proc_run('php',"include/notifier.php","activity", $item_id); } call_hooks('post_local_end', $arr); diff --git a/mod/network.php b/mod/network.php index a19390308..f12471467 100644 --- a/mod/network.php +++ b/mod/network.php @@ -1,253 +1,57 @@ <?php require_once('include/items.php'); +require_once('include/group.php'); +require_once('include/contact_widgets.php'); +require_once('include/conversation.php'); +require_once('include/acl_selectors.php'); + function network_init(&$a) { if(! local_user()) { notice( t('Permission denied.') . EOL); return; } - - $is_a_date_query = false; - - if($a->argc > 1) { - for($x = 1; $x < $a->argc; $x ++) { - if(is_a_date_arg($a->argv[$x])) { - $is_a_date_query = true; - break; - } - } - } - - // convert query string to array and remove first element (wich is friendica args) - $query_array = array(); - parse_str($a->query_string, $query_array); - array_shift($query_array); - - // fetch last used tab and redirect if needed - $sel_tabs = network_query_get_sel_tab($a); - $last_sel_tabs = get_pconfig(local_user(), 'network.view','tab.selected'); - if (is_array($last_sel_tabs)){ - $tab_urls = array( - '/network?f=&order=comment',//all - '/network?f=&order=post', //postord - '/network?f=&conv=1', //conv - '/network/new', //new - '/network?f=&star=1', //starred - '/network?f=&spam=1', //spam - ); - - // redirect if current selected tab is 'no_active' and - // last selected tab is _not_ 'all_active'. - // and this isn't a date query - - if ($sel_tabs[0] == 'active' && $last_sel_tabs[0]!='active' && (! $is_a_date_query)) { - $k = array_search('active', $last_sel_tabs); - - // merge tab querystring with request querystring - $dest_qa = array(); - list($dest_url,$dest_qs) = explode("?", $tab_urls[$k]); - parse_str( $dest_qs, $dest_qa); - $dest_qa = array_merge($query_array, $dest_qa); - $dest_qs = build_querystring($dest_qa); - - // groups filter is in form of "network/nnn". Add it to $dest_url, if it's possible - if ($a->argc==2 && is_numeric($a->argv[1]) && strpos($dest_url, "/",1)===false){ - $dest_url .= "/".$a->argv[1]; - } - -// goaway($a->get_baseurl() . $dest_url."?".$dest_qs); - } - } - - $group_id = ((x($_GET,'gid')) ? intval($_GET['gid']) : 0); - - require_once('include/group.php'); - require_once('include/contact_widgets.php'); - require_once('include/items.php'); - - if(! x($a->page,'aside')) - $a->page['aside'] = ''; - - $search = ((x($_GET,'search')) ? $_GET['search'] : ''); - - if(x($_GET,'save')) { - $r = q("select * from `term` where `uid` = %d and `type` = %d and `term` = '%s' limit 1", - intval(local_user()), - intval(TERM_SAVEDSEARCH), - dbesc($search) - ); - if(! count($r)) { - q("insert into `term` ( `uid`,`type`,`term` ) values ( %d, %d, '%s') ", - intval(local_user()), - intval(TERM_SAVEDSEARCH), - dbesc($search) - ); - } - } - if(x($_GET,'remove')) { - q("delete from `term` where `uid` = %d and `type` = %d and `term` = '%s' limit 1", - intval(local_user()), - intval(TERM_SAVEDSEARCH), - dbesc($search) - ); - } - - - $a->page['aside'] .= group_side('network','network',true,$group_id); - $a->page['aside'] .= posted_date_widget($a->get_baseurl() . '/network',local_user(),false); - - $a->page['aside'] .= saved_searches($search); - $a->page['aside'] .= fileas_widget($a->get_baseurl(true) . '/network',(x($_GET, 'file') ? $_GET['file'] : '')); - - $base = $a->get_baseurl(); - - $a->page['htmlhead'] .= <<< EOT - -<script>$(document).ready(function() { - var a; - a = $("#search-text").autocomplete({ - serviceUrl: '$base/search_ac', - minChars: 2, - width: 350, - }); -}); -</script> -EOT; - - - -} - -function saved_searches($search) { - - if(! feature_enabled(local_user(),'savedsearch')) - return ''; - - $a = get_app(); - - $srchurl = '/network?f=' - . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') - . ((x($_GET,'star')) ? '&star=' . $_GET['star'] : '') - . ((x($_GET,'conv')) ? '&conv=' . $_GET['conv'] : '') - . ((x($_GET,'cmin')) ? '&cmin=' . $_GET['cmin'] : '') - . ((x($_GET,'cmax')) ? '&cmax=' . $_GET['cmax'] : '') - . ((x($_GET,'file')) ? '&file=' . $_GET['file'] : ''); - ; - - $o = ''; - - $r = q("select `tid`,`term` from `term` WHERE `uid` = %d and `type` = %d ", - intval(local_user()), - intval(TERM_SAVEDSEARCH) - ); - - $saved = array(); - - if(count($r)) { - foreach($r as $rr) { - $saved[] = array( - 'id' => $rr['tid'], - 'term' => $rr['term'], - 'displayterm' => htmlspecialchars($rr['term']), - 'encodedterm' => urlencode($rr['term']), - 'delete' => t('Remove term'), - 'selected' => ($search==$rr['term']), - ); - } - } - - - $tpl = get_markup_template("saved_searches_aside.tpl"); - $o = replace_macros($tpl, array( - '$title' => t('Saved Searches'), - '$add' => t('add'), - '$searchbox' => search($search,'netsearch-box',$srchurl,true), - '$saved' => $saved, - )); - - return $o; - -} - -/** - * Return selected tab from query - * - * urls -> returns - * '/network' => $no_active = 'active' - * '/network?f=&order=comment' => $comment_active = 'active' - * '/network?f=&order=post' => $postord_active = 'active' - * '/network?f=&conv=1', => $conv_active = 'active' - * '/network/new', => $new_active = 'active' - * '/network?f=&star=1', => $starred_active = 'active' - * '/network?f=&spam=1', => $spam_active = 'active' - * - * @return Array ( $no_active, $comment_active, $postord_active, $conv_active, $new_active, $starred_active, $spam_active ); - */ -function network_query_get_sel_tab($a) { - $no_active=''; - $starred_active = ''; - $new_active = ''; - $all_active = ''; - $search_active = ''; - $conv_active = ''; - $spam_active = ''; - $postord_active = ''; - - if(x($_GET,'new')) { - $new_active = 'active'; - } - - if(x($_GET,'search')) { - $search_active = 'active'; - } - - if(x($_GET,'star')) { - $starred_active = 'active'; - } - - if(x($_GET,'conv')) { - $conv_active = 'active'; - } - if(x($_GET,'spam')) { - $spam_active = 'active'; - } - - - - if (($new_active == '') - && ($starred_active == '') - && ($conv_active == '') - && ($search_active == '') - && ($spam_active == '')) { - $no_active = 'active'; - } + $channel = $a->get_channel(); + $a->profile_uid = local_user(); + head_set_icon($channel['xchan_photo_s']); - if ($no_active=='active' && x($_GET,'order')) { - switch($_GET['order']){ - case 'post': $postord_active = 'active'; $no_active=''; break; - case 'comment' : $all_active = 'active'; $no_active=''; break; - } - } - - return array($no_active, $all_active, $postord_active, $conv_active, $new_active, $starred_active, $spam_active); } - function network_content(&$a, $update = 0, $load = false) { - require_once('include/conversation.php'); if(! local_user()) { $_SESSION['return_url'] = $a->query_string; return login(false); } + $arr = array('query' => $a->query_string); call_hooks('network_content_init', $arr); + $channel = $a->get_channel(); + + $search = (($_GET['search']) ? $_GET['search'] : ''); + if($search) { + if(strpos($search,'@') === 0) { + $r = q("select abook_id from abook left join xchan on abook_xchan = xchan_hash where xchan_name = '%s' and abook_channel = %d limit 1", + dbesc(substr($search,1)), + intval(local_user()) + ); + if($r) { + $_GET['cid'] = $r[0]['abook_id']; + $search = $_GET['search'] = ''; + } + } + elseif(strpos($search,'#') === 0) { + $search = $_GET['search'] = substr($search,1); + } + } + + $datequery = $datequery2 = ''; @@ -265,84 +69,28 @@ function network_content(&$a, $update = 0, $load = false) { $_GET['order'] = 'post'; if($gid) { + $r = q("SELECT * FROM `groups` WHERE id = %d AND uid = %d LIMIT 1", + intval($gid), + intval(local_user()) + ); + if(! $r) { + if($update) + killme(); + notice( t('No such group') . EOL ); + goaway($a->get_baseurl(true) . '/network'); + // NOTREACHED + } + $group = $gid; - $def_acl = array('allow_gid' => '<' . $group . '>'); + $group_hash = $r[0]['hash']; + $def_acl = array('allow_gid' => '<' . $r[0]['hash'] . '>'); } $o = ''; - // item filter tabs - // TODO: fix this logic, reduce duplication - //$a->page['content'] .= '<div class="tabs-wrapper">'; - - list($no_active, $all_active, $postord_active, $conv_active, $new_active, $starred_active, $spam_active) = network_query_get_sel_tab($a); - // if no tabs are selected, defaults to comments - if ($no_active=='active') $all_active='active'; - //echo "<pre>"; var_dump($no_active, $all_active, $postord_active, $conv_active, $new_active, $starred_active, $bookmarked_active, $spam_active); killme(); - - $cmd = (($datequery) ? '' : $a->cmd); - $len_naked_cmd = strlen(str_replace('/new','',$cmd)); - - // tabs - $tabs = array( - array( - 'label' => t('Commented Order'), - 'url'=>$a->get_baseurl(true) . '/' . $cmd . '?f=&order=comment' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : ''), - 'sel'=>$all_active, - 'title'=> t('Sort by Comment Date'), - ), - array( - 'label' => t('Posted Order'), - 'url'=>$a->get_baseurl(true) . '/' . $cmd . '?f=&order=post' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : ''), - 'sel'=>$postord_active, - 'title' => t('Sort by Post Date'), - ), - - array( - 'label' => t('Personal'), - 'url' => $a->get_baseurl(true) . '/' . $cmd . ((x($_GET,'cid')) ? '/?f=&cid=' . $_GET['cid'] : '') . '&conv=1', - 'sel' => $conv_active, - 'title' => t('Posts that mention or involve you'), - ), - array( - 'label' => t('New'), - 'url' => $a->get_baseurl(true) . '/' . $cmd . ((x($_GET,'cid')) ? '/?f=&cid=' . $_GET['cid'] : '') . '&new=1', - 'sel' => $new_active, - 'title' => t('Activity Stream - by date'), - ), - - ); - - if(feature_enabled(local_user(),'star_posts')) - $tabs[] = array( - 'label' => t('Starred'), - 'url'=>$a->get_baseurl(true) . '/' . $cmd . ((x($_GET,'cid')) ? '/?f=&cid=' . $_GET['cid'] : '') . '&star=1', - 'sel'=>$starred_active, - 'title' => t('Favourite Posts'), - ); - - // Not yet implemented - - if(feature_enabled(local_user(),'spam_filter')) - $tabs[] = array( - 'label' => t('Spam'), - 'url'=>$a->get_baseurl(true) . '/network?f=&spam=1', - 'sel'=> $spam_active, - 'title' => t('Posts flagged as SPAM'), - ); - - - - // save selected tab, but only if not in search or file mode - if(!x($_GET,'search') && !x($_GET,'file')) { - set_pconfig( local_user(), 'network.view','tab.selected',array($all_active, $postord_active, $conv_active, $new_active, $starred_active, $bookmarked_active, $spam_active) ); - } - - - $contact_id = $a->cid; - require_once('include/acl_selectors.php'); + // if no tabs are selected, defaults to comments $cid = ((x($_GET,'cid')) ? intval($_GET['cid']) : 0); $star = ((x($_GET,'star')) ? intval($_GET['star']) : 0); @@ -352,10 +100,10 @@ function network_content(&$a, $update = 0, $load = false) { $spam = ((x($_GET,'spam')) ? intval($_GET['spam']) : 0); $cmin = ((x($_GET,'cmin')) ? intval($_GET['cmin']) : 0); $cmax = ((x($_GET,'cmax')) ? intval($_GET['cmax']) : 99); + $firehose = ((x($_GET,'fh')) ? intval($_GET['fh']) : 0); $file = ((x($_GET,'file')) ? $_GET['file'] : ''); - if(x($_GET,'search') || x($_GET,'file')) $nouveau = true; if($cid) @@ -363,47 +111,31 @@ function network_content(&$a, $update = 0, $load = false) { if(! $update) { - - if(feature_enabled(local_user(),'affinity')) { - $tpl = get_markup_template('main_slider.tpl'); - $o .= replace_macros($tpl,array( - '$val' => intval($cmin) . ';' . intval($cmax), - '$refresh' => t('Refresh'), - '$me' => t('Me'), - '$intimate' => t('Best Friends'), - '$friends' => t('Friends'), - '$coworkers' => t('Co-workers'), - '$oldfriends' => t('Former Friends'), - '$acquaintances' => t('Acquaintances'), - '$world' => t('Everybody') - )); - } - - $arr = array('tabs' => $tabs); - call_hooks('network_tabs', $arr); - - $o .= replace_macros(get_markup_template('common_tabs.tpl'), array('$tabs'=> $arr['tabs'])); - - // --- end item filter tabs - + $o .= network_tabs(); // search terms header if($search) - $o .= '<h2>' . t('Search Results For:') . ' ' . htmlspecialchars($search) . '</h2>'; + $o .= '<h2>' . t('Search Results For:') . ' ' . htmlspecialchars($search, ENT_COMPAT,'UTF-8') . '</h2>'; nav_set_selected('network'); - $celeb = ((($a->user['page-flags'] == PAGE_SOAPBOX) || ($a->user['page-flags'] == PAGE_COMMUNITY)) ? true : false); + $channel_acl = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + $x = array( 'is_owner' => true, - 'allow_location' => $a->user['allow_location'], - 'default_location' => $a->user['default-location'], - 'nickname' => $a->user['nickname'], - 'lockstate' => ((($group) || ($cid) || ($nets) || (is_array($a->user) && ((strlen($a->user['allow_cid'])) || (strlen($a->user['allow_gid'])) || (strlen($a->user['deny_cid'])) || (strlen($a->user['deny_gid']))))) ? 'lock' : 'unlock'), - 'acl' => populate_acl((($group || $cid || $nets) ? $def_acl : $a->user), $celeb), + 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''), + 'default_location' => $channel['channel_location'], + 'nickname' => $channel['channel_address'], + 'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), + 'acl' => populate_acl((($group || $cid) ? $def_acl : $channel_acl)), 'bang' => (($group || $cid) ? '!' : ''), - 'visitor' => 'block', + 'visitor' => true, 'profile_uid' => local_user() ); @@ -426,45 +158,44 @@ function network_content(&$a, $update = 0, $load = false) { $sql_extra = " AND `item`.`parent` IN ( SELECT `parent` FROM `item` WHERE (item_flags & " . intval(ITEM_THREAD_TOP) . ") $sql_options ) "; if($group) { - $r = q("SELECT `name`, `id` FROM `group` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($group), - intval($_SESSION['uid']) - ); - if(! count($r)) { - if($update) - killme(); - notice( t('No such group') . EOL ); - goaway($a->get_baseurl(true) . '/network'); - // NOTREACHED - } + $contact_str = ''; + $contacts = group_get_members($group); + if($contacts) { + foreach($contacts as $c) { + if($contact_str) + $contact_str .= ','; + $contact_str .= "'" . $c['xchan'] . "'"; + } + } + else { + $contact_str = ' 0 '; + info( t('Collection is empty')); + } - $contacts = expand_groups(array($group)); - if((is_array($contacts)) && count($contacts)) { - $contact_str = implode(',',$contacts); - } - else { - $contact_str = ' 0 '; - info( t('Group is empty')); - } + $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND (( author_xchan IN ( $contact_str ) OR owner_xchan in ( $contact_str )) or allow_gid like '" . protect_sprintf('%<' . dbesc($group_hash) . '>%') . "' ) and id = parent and item_restrict = 0 ) "; + + $x = group_rec_byhash(local_user(), $group_hash); + + if($x) + $o = '<h2>' . t('Collection: ') . $x['name'] . '</h2>' . $o; + + + } - $sql_extra = " AND `item`.`parent` IN ( SELECT DISTINCT(`parent`) FROM `item` WHERE 1 $sql_options AND ( `contact-id` IN ( $contact_str ) OR `allow_gid` like '" . protect_sprintf('%<' . intval($group) . '>%') . "' ) and deleted = 0 ) "; - $o = '<h2>' . t('Group: ') . $r[0]['name'] . '</h2>' . $o; - } elseif($cid) { - $r = q("SELECT `id`,`name`,`network`,`writable`,`nurl` FROM `contact` WHERE `id` = %d - AND `blocked` = 0 AND `pending` = 0 LIMIT 1", - intval($cid) - ); - if(count($r)) { - $sql_extra = " AND `item`.`parent` IN ( SELECT DISTINCT(`parent`) FROM `item` WHERE 1 $sql_options AND `contact-id` = " . intval($cid) . " and deleted = 0 ) "; - $o = '<h2>' . t('Contact: ') . $r[0]['name'] . '</h2>' . $o; - } - else { - notice( t('Invalid contact.') . EOL); + $r = q("SELECT abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_channel = %d and not ( abook_flags & " . intval(ABOOK_FLAG_BLOCKED) . ") limit 1", + intval($cid), + intval(local_user()) + ); + if($r) { + $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND uid = " . intval(local_user()) . " AND ( author_xchan = '" . dbesc($r[0]['abook_xchan']) . "' or owner_xchan = '" . dbesc($r[0]['abook_xchan']) . "' ) and item_restrict = 0 ) "; + $o = '<h2>' . t('Connection: ') . $r[0]['xchan_name'] . '</h2>' . $o; + } + else { + notice( t('Invalid connection.') . EOL); goaway($a->get_baseurl(true) . '/network'); - // NOTREACHED - } + } } @@ -473,23 +204,11 @@ function network_content(&$a, $update = 0, $load = false) { // We only launch liveUpdate if you aren't filtering in some incompatible // way and also you aren't writing a comment (discovered in javascript). - $o .= '<div id="live-network"></div>' . "\r\n"; - $o .= "<script> var profile_uid = " . $_SESSION['uid'] - . "; var netargs = '" . substr($a->cmd,8) - . '?f=' - . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') - . ((x($_GET,'search')) ? '&search=' . $_GET['search'] : '') - . ((x($_GET,'star')) ? '&star=' . $_GET['star'] : '') - . ((x($_GET,'order')) ? '&order=' . $_GET['order'] : '') - . ((x($_GET,'liked')) ? '&liked=' . $_GET['liked'] : '') - . ((x($_GET,'conv')) ? '&conv=' . $_GET['conv'] : '') - . ((x($_GET,'spam')) ? '&spam=' . $_GET['spam'] : '') - . ((x($_GET,'cmin')) ? '&cmin=' . $_GET['cmin'] : '') - . ((x($_GET,'cmax')) ? '&cmax=' . $_GET['cmax'] : '') - . ((x($_GET,'file')) ? '&file=' . $_GET['file'] : '') - - . "'; var profile_page = " . $a->pager['page'] . ";</script>"; + if($gid || $cid || $cmin || ($cmax != 99) || $star || $liked || $conv || $spam || $nouveau || $list) + $firehose = 0; + $o .= '<div id="live-network"></div>' . "\r\n"; + $o .= "<script> var profile_uid = " . $_SESSION['uid'] . "; var profile_page = " . $a->pager['page'] . ";</script>"; $a->page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array( '$baseurl' => z_root(), @@ -503,14 +222,17 @@ function network_content(&$a, $update = 0, $load = false) { '$liked' => (($liked) ? $liked : '0'), '$conv' => (($conv) ? $conv : '0'), '$spam' => (($spam) ? $spam : '0'), + '$fh' => (($firehose) ? $firehose : '0'), '$nouveau' => (($nouveau) ? $nouveau : '0'), '$wall' => '0', + '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), '$page' => (($a->pager['page'] != 1) ? $a->pager['page'] : 1), - '$search' => $search, + '$search' => (($search) ? $search : ''), '$order' => $order, '$file' => $file, '$cats' => '', '$dend' => $datequery, + '$mid' => '', '$dbegin' => $datequery2 )); } @@ -542,15 +264,9 @@ function network_content(&$a, $update = 0, $load = false) { } if($conv) { - // find a substring of my profile url that can be normalised - $myurl = $a->get_baseurl() . '/channel/' . $a->user['nickname']; - $myurl = substr($myurl,strpos($myurl,'://')+3); - $myurl = str_replace('www.','',$myurl); - - $sql_extra .= sprintf(" AND `item`.`parent` IN (SELECT distinct(`parent`) from item where ( `item`.`author-link` like '%s' or `item`.`id` in (select term.oid from term where term.type = %d and term.term = '%s' and term.uid = `item`.`uid`))) ", - dbesc(protect_sprintf('%' . $myurl)), - intval(TERM_MENTION), - dbesc(protect_sprintf($a->user['username'])) + $sql_extra .= sprintf(" AND parent IN (SELECT distinct(parent) from item where ( author_xchan like '%s' or ( item_flags & %d ))) ", + dbesc(protect_sprintf($channel['channel_hash'])), + intval(ITEM_MENTIONSME) ); } @@ -562,7 +278,7 @@ function network_content(&$a, $update = 0, $load = false) { } else { $itemspage = get_pconfig(local_user(),'system','itemspage'); - $a->set_pager_itemspage(((intval($itemspage)) ? $itemspage : 40)); + $a->set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); $pager_sql = sprintf(" LIMIT %d, %d ",intval($a->pager['start']), intval($a->pager['itemspage'])); } @@ -588,28 +304,35 @@ function network_content(&$a, $update = 0, $load = false) { } + if($firehose && (! get_config('system','disable_discover_tab'))) { + require_once('include/identity.php'); + $sys = get_sys_channel(); + $uids = " and item.uid = " . intval($sys['channel_id']) . " "; + $a->data['firehose'] = intval($sys['channel_id']); + } + else { + $uids = " and item.uid = " . local_user() . " "; + } + $simple_update = (($update) ? " and ( item.item_flags & " . intval(ITEM_UNSEEN) . " ) " : ''); if($load) $simple_update = ''; - $start = dba_timer(); - if($nouveau && $load) { // "New Item View" - show all items unthreaded in reverse created date order $items = q("SELECT `item`.*, `item`.`id` AS `item_id` FROM `item` - WHERE `item`.`uid` = %d AND item_restrict = 0 + WHERE true $uids AND item_restrict = 0 $simple_update $sql_extra $sql_nets - ORDER BY `item`.`received` DESC $pager_sql ", - intval($_SESSION['uid']) + ORDER BY `item`.`received` DESC $pager_sql " ); require_once('include/items.php'); xchan_query($items); - $items = fetch_post_tags($items); + $items = fetch_post_tags($items,true); } elseif($update) { @@ -624,93 +347,72 @@ function network_content(&$a, $update = 0, $load = false) { // Fetch a page full of parent items for this page - $r = q("SELECT item.id AS item_id FROM item + $r = q("SELECT distinct item.id AS item_id FROM item left join abook on item.author_xchan = abook.abook_xchan - WHERE item.uid = %d AND item.item_restrict = 0 + WHERE true $uids AND item.item_restrict = 0 AND item.parent = item.id and ((abook.abook_flags & %d) = 0 or abook.abook_flags is null) $sql_extra3 $sql_extra $sql_nets ORDER BY item.$ordering DESC $pager_sql ", - intval(local_user()), intval(ABOOK_FLAG_BLOCKED) ); + } else { - // update - $r = q("SELECT item.parent AS item_id FROM item - left join abook on item.author_xchan = abook.abook_xchan - WHERE item.uid = %d AND item.item_restrict = 0 $simple_update - and ((abook.abook_flags & %d) = 0 or abook.abook_flags is null) - $sql_extra3 $sql_extra $sql_nets ", - intval(local_user()), - intval(ABOOK_FLAG_BLOCKED) - ); - + if(! $firehose) { + // update + $r = q("SELECT item.parent AS item_id FROM item + left join abook on item.author_xchan = abook.abook_xchan + WHERE true $uids AND item.item_restrict = 0 $simple_update + and ((abook.abook_flags & %d) = 0 or abook.abook_flags is null) + $sql_extra3 $sql_extra $sql_nets ", + intval(ABOOK_FLAG_BLOCKED) + ); + } } - // Then fetch all the children of the parents that are on this page + $parents_str = ''; + $update_unseen = ''; if($r) { $parents_str = ids_to_querystr($r,'item_id'); $items = q("SELECT `item`.*, `item`.`id` AS `item_id` FROM `item` - WHERE `item`.`uid` = %d AND `item`.`item_restrict` = 0 + WHERE true $uids AND `item`.`item_restrict` = 0 AND `item`.`parent` IN ( %s ) $sql_extra ", - intval(local_user()), dbesc($parents_str) ); xchan_query($items); - - $items = fetch_post_tags($items); - + $items = fetch_post_tags($items,true); $items = conv_sort($items,$ordering); - - //logger('items: ' . print_r($items,true)); - } else { $items = array(); } - } - // logger('items: ' . count($items)); + if($parents_str) + $update_unseen = ' AND parent IN ( ' . dbesc($parents_str) . ' )'; - // We aren't going to try and figure out at the item, group, and page - // level which items you've seen and which you haven't. If you're looking - // at the top level network page just mark everything seen. + } - if((! $group) && (! $cid) && (! $star)) { + if(($update_unseen) && (! $firehose)) $r = q("UPDATE `item` SET item_flags = ( item_flags ^ %d) - WHERE (item_flags & %d) AND `uid` = %d", + WHERE (item_flags & %d) AND `uid` = %d $update_unseen ", intval(ITEM_UNSEEN), intval(ITEM_UNSEEN), intval(local_user()) ); - } - -// fixme - // Set this so that the conversation function can find out contact info for our wall-wall items - $a->page_contact = $a->contact; $mode = (($nouveau) ? 'network-new' : 'network'); - $first = dba_timer(); - $o .= conversation($a,$items,$mode,$update,'client'); - - $second = dba_timer(); - - if(! $update) + if(($items) && (! $update)) $o .= alt_pager($a,count($items)); -// logger('parent dba_timer: ' . sprintf('%01.4f',$first - $start)); -// logger('child dba_timer: ' . sprintf('%01.4f',$second - $first)); - - return $o; } diff --git a/mod/new_channel.php b/mod/new_channel.php index 8d0776ff0..eafef2c08 100644 --- a/mod/new_channel.php +++ b/mod/new_channel.php @@ -111,7 +111,7 @@ function new_channel_content(&$a) { '$help_name' => t('Examples: "Bob Jameson", "Lisa and her Horses", "Soccer", "Aviation Group" '), '$label_nick' => t('Choose a short nickname'), '$nick_desc' => t('Your nickname will be used to create an easily remembered channel address (like an email address) which you can share with others.'), - '$label_import' => t('Check this box to import an existing channel file from another location'), + '$label_import' => t('Or <a href="import">import an existing channel</a> from another location'), '$name' => $name, '$nickname' => $nickname, '$submit' => t('Create') diff --git a/mod/nogroup.php b/mod/nogroup.php deleted file mode 100644 index bd1ec82ed..000000000 --- a/mod/nogroup.php +++ /dev/null @@ -1,65 +0,0 @@ -<?php - -require_once('include/Contact.php'); -require_once('include/socgraph.php'); -require_once('include/contact_selectors.php'); - -function nogroup_init(&$a) { - - if(! local_user()) - return; - - require_once('include/group.php'); - require_once('include/contact_widgets.php'); - - if(! x($a->page,'aside')) - $a->page['aside'] = ''; - - $a->page['aside'] .= group_side('contacts','group',false,0,$contact_id); -} - - -function nogroup_content(&$a) { - - if(! local_user()) { - notice( t('Permission denied.') . EOL); - return ''; - } - - require_once('include/Contact.php'); - $r = contacts_not_grouped(local_user()); - if(count($r)) { - $a->set_pager_total($r[0]['total']); - } - $r = contacts_not_grouped(local_user(),$a->pager['start'],$a->pager['itemspage']); - if(count($r)) { - foreach($r as $rr) { - - - $contacts[] = array( - 'img_hover' => sprintf( t('Visit %s\'s profile [%s]'),$rr['name'],$rr['url']), - 'edit_hover' => t('Edit contact'), - 'photo_menu' => contact_photo_menu($rr), - 'id' => $rr['id'], - 'alt_text' => $alt_text, - 'dir_icon' => $dir_icon, - 'thumb' => $rr['thumb'], - 'name' => $rr['name'], - 'username' => $rr['name'], - 'sparkle' => $sparkle, - 'itemurl' => $rr['url'], - 'url' => $url, - 'network' => network_to_name($rr['network']), - ); - } - } - $tpl = get_markup_template("nogroup-template.tpl"); - $o .= replace_macros($tpl,array( - '$header' => t('Contacts who are not members of a group'), - '$contacts' => $contacts, - '$paginate' => paginate($a), - )); - - return $o; - -} diff --git a/mod/notes.php b/mod/notes.php new file mode 100644 index 000000000..84f8a7093 --- /dev/null +++ b/mod/notes.php @@ -0,0 +1,24 @@ +<?php /** @file */ + +function notes_init(&$a) { + + if(! local_user()) + return; + + $ret = array('success' => true); + if($_REQUEST['note_text'] || $_REQUEST['note_text'] == '') { + $body = escape_tags($_REQUEST['note_text']); + set_pconfig(local_user(),'notes','text',$body); + } + + // push updates to channel clones + + if((argc() > 1) && (argv(1) === 'sync')) { + require_once('include/zot.php'); + build_sync_packet(); + } + + logger('notes saved.', LOGGER_DEBUG); + json_return_and_die($ret); + +} diff --git a/mod/notifications.php b/mod/notifications.php index 7d861037c..09f89e88a 100644 --- a/mod/notifications.php +++ b/mod/notifications.php @@ -70,242 +70,7 @@ function notifications_content(&$a) { nav_set_selected('notifications'); $o = ''; - $tabs = array( - array( - 'label' => t('System'), - 'url'=>$a->get_baseurl(true) . '/notifications/system', - 'sel'=> (($a->argv[1] == 'system') ? 'active' : ''), - ), - array( - 'label' => t('Network'), - 'url'=>$a->get_baseurl(true) . '/notifications/network', - 'sel'=> (($a->argv[1] == 'network') ? 'active' : ''), - ), - array( - 'label' => t('Personal'), - 'url'=>$a->get_baseurl(true) . '/notifications/personal', - 'sel'=> (($a->argv[1] == 'personal') ? 'active' : ''), - ), - array( - 'label' => t('Home'), - 'url' => $a->get_baseurl(true) . '/notifications/home', - 'sel'=> (($a->argv[1] == 'home') ? 'active' : ''), - ), - array( - 'label' => t('Introductions'), - 'url' => $a->get_baseurl(true) . '/notifications/intros', - 'sel'=> (($a->argv[1] == 'intros') ? 'active' : ''), - ), - array( - 'label' => t('Messages'), - 'url' => $a->get_baseurl(true) . '/message', - 'sel'=> '', - ), - ); - - $o = ""; - - - if( (($a->argc > 1) && ($a->argv[1] == 'intros')) || (($a->argc == 1))) { - nav_set_selected('introductions'); - if(($a->argc > 2) && ($a->argv[2] == 'all')) - $sql_extra = ''; - else - $sql_extra = " AND `ignore` = 0 "; - - $notif_tpl = get_markup_template('notifications.tpl'); - - $notif_content .= '<a href="' . ((strlen($sql_extra)) ? 'notifications/intros/all' : 'notifications/intros' ) . '" id="notifications-show-hide-link" >' - . ((strlen($sql_extra)) ? t('Show Ignored Requests') : t('Hide Ignored Requests')) . '</a></div>' . "\r\n"; - - $r = q("SELECT COUNT(*) AS `total` FROM `intro` - WHERE `intro`.`uid` = %d $sql_extra AND `intro`.`blocked` = 0 ", - intval($_SESSION['uid']) - ); - if($r && count($r)) { - $a->set_pager_total($r[0]['total']); - $a->set_pager_itemspage(20); - } - - $r = q("SELECT `intro`.`id` AS `intro_id`, `intro`.*, `contact`.*, `fcontact`.`name` AS `fname`,`fcontact`.`url` AS `furl`,`fcontact`.`photo` AS `fphoto`,`fcontact`.`request` AS `frequest` - FROM `intro` LEFT JOIN `contact` ON `contact`.`id` = `intro`.`contact-id` LEFT JOIN `fcontact` ON `intro`.`fid` = `fcontact`.`id` - WHERE `intro`.`uid` = %d $sql_extra AND `intro`.`blocked` = 0 ", - intval($_SESSION['uid'])); - - if(($r !== false) && (count($r))) { - - $sugg = get_markup_template('suggestions.tpl'); - $tpl = get_markup_template("intros.tpl"); - - foreach($r as $rr) { - if($rr['fid']) { - $return_addr = bin2hex($a->user['nickname'] . '@' . $a->get_hostname() . (($a->path) ? '/' . $a->path : '')); - $notif_content .= replace_macros($sugg,array( - '$str_notifytype' => t('Notification type: '), - '$notify_type' => t('Friend Suggestion'), - '$intro_id' => $rr['intro_id'], - '$madeby' => sprintf( t('suggested by %s'),$rr['name']), - '$contact_id' => $rr['contact-id'], - '$photo' => ((x($rr,'fphoto')) ? $rr['fphoto'] : "images/person-175.jpg"), - '$fullname' => $rr['fname'], - '$url' => zid($rr['furl']), - '$hidden' => array('hidden', t('Hide this contact from others'), ($rr['hidden'] == 1), ''), - '$activity' => array('activity', t('Post a new friend activity'), (intval(get_pconfig(local_user(),'system','post_newfriend')) ? '1' : 0), t('if applicable')), - - '$knowyou' => $knowyou, - '$approve' => t('Approve'), - '$note' => $rr['note'], - '$request' => $rr['frequest'] . '?addr=' . $return_addr, - '$ignore' => t('Ignore'), - '$discard' => t('Discard') - - )); - - continue; - - } - $friend_selected = (($rr['network'] !== NETWORK_OSTATUS) ? ' checked="checked" ' : ' disabled '); - $fan_selected = (($rr['network'] === NETWORK_OSTATUS) ? ' checked="checked" disabled ' : ''); - $dfrn_tpl = get_markup_template('netfriend.tpl'); - - $knowyou = ''; - $dfrn_text = ''; - - if($rr['network'] === NETWORK_DFRN || $rr['network'] === NETWORK_DIASPORA) { - if($rr['network'] === NETWORK_DFRN) - $knowyou = t('Claims to be known to you: ') . (($rr['knowyou']) ? t('yes') : t('no')); - else - $knowyou = ''; - $dfrn_text = replace_macros($dfrn_tpl,array( - '$intro_id' => $rr['intro_id'], - '$friend_selected' => $friend_selected, - '$fan_selected' => $fan_selected, - '$approve_as' => t('Approve as: '), - '$as_friend' => t('Friend'), - '$as_fan' => (($rr['network'] == NETWORK_DIASPORA) ? t('Sharer') : t('Fan/Admirer')) - )); - } - - $notif_content .= replace_macros($tpl,array( - '$str_notifytype' => t('Notification type: '), - '$notify_type' => (($rr['network'] !== NETWORK_OSTATUS) ? t('Friend/Connect Request') : t('New Follower')), - '$dfrn_text' => $dfrn_text, - '$dfrn_id' => $rr['issued_id'], - '$uid' => $_SESSION['uid'], - '$intro_id' => $rr['intro_id'], - '$contact_id' => $rr['contact-id'], - '$photo' => ((x($rr,'photo')) ? $rr['photo'] : "images/person-175.jpg"), - '$fullname' => $rr['name'], - '$hidden' => array('hidden', t('Hide this contact from others'), ($rr['hidden'] == 1), ''), - '$activity' => array('activity', t('Post a new friend activity'), (intval(get_pconfig(local_user(),'system','post_newfriend')) ? '1' : 0), t('if applicable')), - '$url' => zid($rr['url']), - '$knowyou' => $knowyou, - '$approve' => t('Approve'), - '$note' => $rr['note'], - '$ignore' => t('Ignore'), - '$discard' => t('Discard') - - )); - } - } - else - info( t('No introductions.') . EOL); - - $o .= replace_macros($notif_tpl,array( - '$notif_header' => t('Notifications'), - '$tabs' => $tabs, - '$notif_content' => $notif_content, - )); - - $o .= paginate($a); - return $o; - - } else if (($a->argc > 1) && ($a->argv[1] == 'network')) { - - $notif_tpl = get_markup_template('notifications.tpl'); - - $r = q("SELECT `item`.`id`,`item`.`parent`, `item`.`verb`, `item`.`author-name`, - `item`.`author-link`, `item`.`author-avatar`, `item`.`created`, `item`.`object` as `object`, - `pitem`.`author-name` as `pname`, `pitem`.`author-link` as `plink` - FROM `item` INNER JOIN `item` as `pitem` ON `pitem`.`id`=`item`.`parent` - WHERE `item`.`unseen` = 1 AND `item`.`visible` = 1 AND - `item`.`deleted` = 0 AND `item`.`uid` = %d AND `item`.`wall` = 0 ORDER BY `item`.`created` DESC" , - intval(local_user()) - ); - - $tpl_item_likes = get_markup_template('notifications_likes_item.tpl'); - $tpl_item_dislikes = get_markup_template('notifications_dislikes_item.tpl'); - $tpl_item_friends = get_markup_template('notifications_friends_item.tpl'); - $tpl_item_comments = get_markup_template('notifications_comments_item.tpl'); - $tpl_item_posts = get_markup_template('notifications_posts_item.tpl'); - - $notif_content = ''; - - if (count($r) > 0) { - - foreach ($r as $it) { - switch($it['verb']){ - case ACTIVITY_LIKE: - $notif_content .= replace_macros($tpl_item_likes,array( - '$item_link' => $a->get_baseurl(true).'/display/'.$a->user['nickname']."/".$it['parent'], - '$item_image' => $it['author-avatar'], - '$item_text' => sprintf( t("%s liked %s's post"), $it['author-name'], $it['pname']), - '$item_when' => relative_date($it['created']) - )); - break; - - case ACTIVITY_DISLIKE: - $notif_content .= replace_macros($tpl_item_dislikes,array( - '$item_link' => $a->get_baseurl(true).'/display/'.$a->user['nickname']."/".$it['parent'], - '$item_image' => $it['author-avatar'], - '$item_text' => sprintf( t("%s disliked %s's post"), $it['author-name'], $it['pname']), - '$item_when' => relative_date($it['created']) - )); - break; - - case ACTIVITY_FRIEND: - - $xmlhead="<"."?xml version='1.0' encoding='UTF-8' ?".">"; - $obj = parse_xml_string($xmlhead.$it['object']); - $it['fname'] = $obj->title; - - $notif_content .= replace_macros($tpl_item_friends,array( - '$item_link' => $a->get_baseurl(true).'/display/'.$a->user['nickname']."/".$it['parent'], - '$item_image' => $it['author-avatar'], - '$item_text' => sprintf( t("%s is now friends with %s"), $it['author-name'], $it['fname']), - '$item_when' => relative_date($it['created']) - )); - break; - - default: - $item_text = (($it['id'] == $it['parent']) - ? sprintf( t("%s created a new post"), $it['author-name']) - : sprintf( t("%s commented on %s's post"), $it['author-name'], $it['pname'])); - $tpl = (($it['id'] == $it['parent']) ? $tpl_item_posts : $tpl_item_comments); - - $notif_content .= replace_macros($tpl,array( - '$item_link' => $a->get_baseurl(true).'/display/'.$a->user['nickname']."/".$it['parent'], - '$item_image' => $it['author-avatar'], - '$item_text' => $item_text, - '$item_when' => relative_date($it['created']) - )); - } - } - - } else { - - $notif_content = t('No more network notifications.'); - } - - $o .= replace_macros($notif_tpl,array( - '$notif_header' => t('Network Notifications'), - '$tabs' => $tabs, - '$notif_content' => $notif_content, - )); - - } else if (($a->argc > 1) && ($a->argv[1] == 'system')) { - $notif_tpl = get_markup_template('notifications.tpl'); $not_tpl = get_markup_template('notify.tpl'); @@ -316,6 +81,7 @@ function notifications_content(&$a) { ); if (count($r) > 0) { + $notifications_available =1; foreach ($r as $it) { $notif_content .= replace_macros($not_tpl,array( '$item_link' => $a->get_baseurl(true).'/notify/view/'. $it['id'], @@ -330,187 +96,10 @@ function notifications_content(&$a) { $o .= replace_macros($notif_tpl,array( '$notif_header' => t('System Notifications'), - '$tabs' => $tabs, + '$notif_link_mark_seen' => t('Mark all system notifications seen'), '$notif_content' => $notif_content, + '$notifications_available' => $notifications_available, )); - } else if (($a->argc > 1) && ($a->argv[1] == 'personal')) { - - $notif_tpl = get_markup_template('notifications.tpl'); - - $myurl = $a->get_baseurl(true) . '/channel/'. $a->user['nickname']; - $myurl = substr($myurl,strpos($myurl,'://')+3); - $myurl = str_replace(array('www.','.'),array('','\\.'),$myurl); - $diasp_url = str_replace('/channel/','/u/',$myurl); - $sql_extra .= sprintf(" AND ( `item`.`author-link` regexp '%s' or `item`.`tag` regexp '%s' or `item`.`tag` regexp '%s' ) ", - dbesc($myurl . '$'), - dbesc($myurl . '\\]'), - dbesc($diasp_url . '\\]') - ); - - - $r = q("SELECT `item`.`id`,`item`.`parent`, `item`.`verb`, `item`.`author-name`, - `item`.`author-link`, `item`.`author-avatar`, `item`.`created`, `item`.`object` as `object`, - `pitem`.`author-name` as `pname`, `pitem`.`author-link` as `plink` - FROM `item` INNER JOIN `item` as `pitem` ON `pitem`.`id`=`item`.`parent` - WHERE `item`.`unseen` = 1 AND `item`.`visible` = 1 - $sql_extra - AND `item`.`deleted` = 0 AND `item`.`uid` = %d AND `item`.`wall` = 0 ORDER BY `item`.`created` DESC" , - intval(local_user()) - ); - - $tpl_item_likes = get_markup_template('notifications_likes_item.tpl'); - $tpl_item_dislikes = get_markup_template('notifications_dislikes_item.tpl'); - $tpl_item_friends = get_markup_template('notifications_friends_item.tpl'); - $tpl_item_comments = get_markup_template('notifications_comments_item.tpl'); - $tpl_item_posts = get_markup_template('notifications_posts_item.tpl'); - - $notif_content = ''; - - if (count($r) > 0) { - - foreach ($r as $it) { - switch($it['verb']){ - case ACTIVITY_LIKE: - $notif_content .= replace_macros($tpl_item_likes,array( - '$item_link' => $a->get_baseurl(true).'/display/'.$a->user['nickname']."/".$it['parent'], - '$item_image' => $it['author-avatar'], - '$item_text' => sprintf( t("%s liked %s's post"), $it['author-name'], $it['pname']), - '$item_when' => relative_date($it['created']) - )); - break; - - case ACTIVITY_DISLIKE: - $notif_content .= replace_macros($tpl_item_dislikes,array( - '$item_link' => $a->get_baseurl(true).'/display/'.$a->user['nickname']."/".$it['parent'], - '$item_image' => $it['author-avatar'], - '$item_text' => sprintf( t("%s disliked %s's post"), $it['author-name'], $it['pname']), - '$item_when' => relative_date($it['created']) - )); - break; - - case ACTIVITY_FRIEND: - - $xmlhead="<"."?xml version='1.0' encoding='UTF-8' ?".">"; - $obj = parse_xml_string($xmlhead.$it['object']); - $it['fname'] = $obj->title; - - $notif_content .= replace_macros($tpl_item_friends,array( - '$item_link' => $a->get_baseurl(true).'/display/'.$a->user['nickname']."/".$it['parent'], - '$item_image' => $it['author-avatar'], - '$item_text' => sprintf( t("%s is now friends with %s"), $it['author-name'], $it['fname']), - '$item_when' => relative_date($it['created']) - )); - break; - - default: - $item_text = (($it['id'] == $it['parent']) - ? sprintf( t("%s created a new post"), $it['author-name']) - : sprintf( t("%s commented on %s's post"), $it['author-name'], $it['pname'])); - $tpl = (($it['id'] == $it['parent']) ? $tpl_item_posts : $tpl_item_comments); - - $notif_content .= replace_macros($tpl,array( - '$item_link' => $a->get_baseurl(true).'/display/'.$a->user['nickname']."/".$it['parent'], - '$item_image' => $it['author-avatar'], - '$item_text' => $item_text, - '$item_when' => relative_date($it['created']) - )); - } - } - - } else { - - $notif_content = t('No more personal notifications.'); - } - - $o .= replace_macros($notif_tpl,array( - '$notif_header' => t('Personal Notifications'), - '$tabs' => $tabs, - '$notif_content' => $notif_content, - )); - - - - - - - } else if (($a->argc > 1) && ($a->argv[1] == 'home')) { - - $notif_tpl = get_markup_template('notifications.tpl'); - - $r = q("SELECT `item`.`id`,`item`.`parent`, `item`.`verb`, `item`.`author-name`, - `item`.`author-link`, `item`.`author-avatar`, `item`.`created`, `item`.`object` as `object`, - `pitem`.`author-name` as `pname`, `pitem`.`author-link` as `plink` - FROM `item` INNER JOIN `item` as `pitem` ON `pitem`.`id`=`item`.`parent` - WHERE `item`.`unseen` = 1 AND `item`.`visible` = 1 AND - `item`.`deleted` = 0 AND `item`.`uid` = %d AND `item`.`wall` = 1 ORDER BY `item`.`created` DESC", - intval(local_user()) - ); - - $tpl_item_likes = get_markup_template('notifications_likes_item.tpl'); - $tpl_item_dislikes = get_markup_template('notifications_dislikes_item.tpl'); - $tpl_item_friends = get_markup_template('notifications_friends_item.tpl'); - $tpl_item_comments = get_markup_template('notifications_comments_item.tpl'); - - $notif_content = ''; - - if (count($r) > 0) { - - foreach ($r as $it) { - switch($it['verb']){ - case ACTIVITY_LIKE: - $notif_content .= replace_macros($tpl_item_likes,array( - '$item_link' => $a->get_baseurl(true).'/display/'.$a->user['nickname']."/".$it['parent'], - '$item_image' => $it['author-avatar'], - '$item_text' => sprintf( t("%s liked %s's post"), $it['author-name'], $it['pname']), - '$item_when' => relative_date($it['created']) - )); - - break; - case ACTIVITY_DISLIKE: - $notif_content .= replace_macros($tpl_item_dislikes,array( - '$item_link' => $a->get_baseurl(true).'/display/'.$a->user['nickname']."/".$it['parent'], - '$item_image' => $it['author-avatar'], - '$item_text' => sprintf( t("%s disliked %s's post"), $it['author-name'], $it['pname']), - '$item_when' => relative_date($it['created']) - )); - - break; - case ACTIVITY_FRIEND: - - $xmlhead="<"."?xml version='1.0' encoding='UTF-8' ?".">"; - $obj = parse_xml_string($xmlhead.$it['object']); - $it['fname'] = $obj->title; - - $notif_content .= replace_macros($tpl_item_friends,array( - '$item_link' => $a->get_baseurl(true).'/display/'.$a->user['nickname']."/".$it['parent'], - '$item_image' => $it['author-avatar'], - '$item_text' => sprintf( t("%s is now friends with %s"), $it['author-name'], $it['fname']), - '$item_when' => relative_date($it['created']) - )); - - break; - default: - $notif_content .= replace_macros($tpl_item_comments,array( - '$item_link' => $a->get_baseurl(true).'/display/'.$a->user['nickname']."/".$it['parent'], - '$item_image' => $it['author-avatar'], - '$item_text' => sprintf( t("%s commented on %s's post"), $it['author-name'], $it['pname']), - '$item_when' => relative_date($it['created']) - )); - } - } - - } else { - $notif_content = t('No more home notifications.'); - } - - $o .= replace_macros($notif_tpl,array( - '$notif_header' => t('Home Notifications'), - '$tabs' => $tabs, - '$notif_content' => $notif_content, - )); - } - - $o .= paginate($a); return $o; } diff --git a/mod/notify.php b/mod/notify.php index dd26bfe7e..72534c7fd 100644 --- a/mod/notify.php +++ b/mod/notify.php @@ -10,27 +10,18 @@ function notify_init(&$a) { intval(argv(2)), intval(local_user()) ); - if(count($r)) { - q("update notify set seen = 1 where ( link = '%s' or ( parent != 0 and parent = %d and otype = '%s' )) and uid = %d", - dbesc($r[0]['link']), - intval($r[0]['parent']), + if($r) { + q("update notify set seen = 1 where (( parent != '' and parent = '%s' and otype = '%s' ) or link = '%s' ) and uid = %d", + dbesc($r[0]['parent']), dbesc($r[0]['otype']), + dbesc($r[0]['link']), intval(local_user()) ); goaway($r[0]['link']); } - goaway($a->get_baseurl(true)); } - if(argc() > 2 && argv(1) === 'mark' && argv(2) === 'all' ) { - $r = q("update notify set seen = 1 where uid = %d", - intval(local_user()) - ); - $j = json_encode(array('result' => ($r) ? 'success' : 'fail')); - echo $j; - killme(); - } } @@ -48,7 +39,7 @@ function notify_content(&$a) { intval(local_user()) ); - if (count($r) > 0) { + if($r) { foreach ($r as $it) { $notif_content .= replace_macros($not_tpl,array( '$item_link' => $a->get_baseurl(true).'/notify/view/'. $it['id'], diff --git a/mod/oembed.php b/mod/oembed.php index 720a6d72b..a053a8c98 100644 --- a/mod/oembed.php +++ b/mod/oembed.php @@ -19,8 +19,7 @@ function oembed_init(&$a){ else { echo "<html><body>"; - $url = base64url_decode($argv(1)); - $j = oembed_fetch_url($url); + $j = oembed_fetch_url(base64url_decode(argv(1))); echo $j->html; // logger('mod-oembed ' . $j->html, LOGGER_ALL); echo "</body></html>"; diff --git a/mod/oexchange.php b/mod/oexchange.php index 791a493ff..27c8b388d 100644 --- a/mod/oexchange.php +++ b/mod/oexchange.php @@ -15,6 +15,21 @@ function oexchange_init(&$a) { function oexchange_content(&$a) { if(! local_user()) { + if(remote_user()) { + $observer = $a->get_observer(); + if($observer && $observer['xchan_url']) { + $parsed = @parse_url($observer['xchan_url']); + if(! $parsed) { + notice( t('Unable to find your hub.') . EOL); + return; + } + $url = $parsed['scheme'] . '://' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : ''); + $url .= '/oexchange'; + $result = z_post_url($url,$_REQUEST); + json_return_and_die($result); + } + } + return login(false); } @@ -32,18 +47,19 @@ function oexchange_content(&$a) { $tags = (((x($_REQUEST,'tags')) && strlen($_REQUEST['tags'])) ? '&tags=' . urlencode(notags(trim($_REQUEST['tags']))) : ''); - $s = fetch_url($a->get_baseurl() . '/parse_url?f=&url=' . $url . $title . $description . $tags); + $ret = z_fetch_url($a->get_baseurl() . '/parse_url?f=&url=' . $url . $title . $description . $tags); + + if($ret['success']) + $s = $ret['body']; if(! strlen($s)) return; - require_once('include/html2bbcode.php'); - $post = array(); $post['profile_uid'] = local_user(); $post['return'] = '/oexchange/done' ; - $post['body'] = html2bbcode($s); + $post['body'] = $s; $post['type'] = 'wall'; $_REQUEST = $post; diff --git a/mod/online.php b/mod/online.php new file mode 100644 index 000000000..c6500347a --- /dev/null +++ b/mod/online.php @@ -0,0 +1,11 @@ +<?php /** @file */ + +function online_init(&$a) { + + $ret = array('result' => false); + if(argc() != 2) + json_return_and_die($ret); + + $ret = get_online_status(argv(1)); + json_return_and_die($ret); +} diff --git a/mod/openid.php b/mod/openid.php new file mode 100644 index 000000000..2112e0af4 --- /dev/null +++ b/mod/openid.php @@ -0,0 +1,191 @@ +<?php + + +require_once('library/openid/openid.php'); +require_once('include/auth.php'); + +function openid_content(&$a) { + + $noid = get_config('system','disable_openid'); + if($noid) + goaway(z_root()); + + logger('mod_openid ' . print_r($_REQUEST,true), LOGGER_DATA); + + if(x($_REQUEST,'openid_mode')) { + + $openid = new LightOpenID(z_root()); + + if($openid->validate()) { + + logger('openid: validate'); + + $authid = normalise_openid($_REQUEST['openid_identity']); + + if(! strlen($authid)) { + logger( t('OpenID protocol error. No ID returned.') . EOL); + goaway(z_root()); + } + + $x = match_openid($authid); + if($x) { + + $r = q("select * from channel where channel_id = %d limit 1", + intval($x) + ); + if($r) { + $y = q("select * from account where account_id = %d limit 1", + intval($r[0]['channel_account_id']) + ); + if($y) { + foreach($y as $record) { + if(($record['account_flags'] == ACCOUNT_OK) || ($record['account_flags'] == ACCOUNT_UNVERIFIED)) { + logger('mod_openid: openid success for ' . $x[0]['channel_name']); + $_SESSION['uid'] = $r[0]['channel_id']; + $_SESSION['account_id'] = $r[0]['channel_account_id']; + $_SESSION['authenticated'] = true; + authenticate_success($record,true,true,true,true); + goaway(z_root()); + } + } + } + } + } + + // Successful OpenID login - but we can't match it to an existing account. + // See if they've got an xchan + + $r = q("select * from xconfig left join xchan on xchan_hash = xconfig.xchan where cat = 'system' and k = 'openid' and v = '%s' limit 1", + dbesc($authid) + ); + + if($r) { + $_SESSION['authenticated'] = 1; + $_SESSION['visitor_id'] = $r[0]['xchan_hash']; + $_SESSION['my_url'] = $r[0]['xchan_url']; + $_SESSION['my_address'] = $r[0]['xchan_addr']; + $arr = array('xchan' => $r[0], 'session' => $_SESSION); + call_hooks('magic_auth_openid_success',$arr); + $a->set_observer($r[0]); + require_once('include/security.php'); + $a->set_groups(init_groups_visitor($_SESSION['visitor_id'])); + info(sprintf( t('Welcome %s. Remote authentication successful.'),$r[0]['xchan_name'])); + logger('mod_openid: remote auth success from ' . $r[0]['xchan_addr']); + if($_SESSION['return_url']) + goaway($_SESSION['return_url']); + goaway(z_root()); + } + + // no xchan... + // create one. + // We should probably probe the openid url and figure out if they have any kind of social presence we might be able to + // scrape some identifying info from. + + $name = $authid; + $url = trim($_REQUEST['openid_identity'],'/'); + if(strpos($url,'http') === false) + $url = 'https://' . $url; + $pphoto = get_default_profile_photo(); + $parsed = @parse_url($url); + if($parsed) { + $host = $parsed['host']; + } + + $attr = $openid->getAttributes(); + + if(is_array($attr) && count($attr)) { + foreach($attr as $k => $v) { + if($k === 'namePerson/friendly') + $nick = notags(trim($v)); + if($k === 'namePerson/first') + $first = notags(trim($v)); + if($k === 'namePerson') + $name = notags(trim($v)); + if($k === 'contact/email') + $addr = notags(trim($v)); + if($k === 'media/image/aspect11') + $photosq = trim($v); + if($k === 'media/image/default') + $photo_other = trim($v); + } + } + if(! $nick) { + if($first) + $nick = $first; + else + $nick = $name; + } + + require_once('library/urlify/URLify.php'); + $x = strtolower(URLify::transliterate($nick)); + if($nick & $host) + $addr = $nick . '@' . $host; + $network = 'unknown'; + + if($photosq) + $pphoto = $photosq; + elseif($photo_other) + $pphoto = $photo_other; + + $x = q("insert into xchan ( xchan_hash, xchan_guid, xchan_guid_sig, xchan_pubkey, xchan_photo_mimetype, + xchan_photo_l, xchan_addr, xchan_url, xchan_connurl, xchan_follow, xchan_connpage, xchan_name, xchan_network, xchan_photo_date, + xchan_name_date, xchan_flags) + values ( '%s', '%s', '%s', '%s' , '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d) ", + dbesc($url), + dbesc(''), + dbesc(''), + dbesc(''), + dbesc('image/jpeg'), + dbesc($pphoto), + dbesc($addr), + dbesc($url), + dbesc(''), + dbesc(''), + dbesc(''), + dbesc($name), + dbesc($network), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + intval(XCHAN_FLAGS_HIDDEN) + ); + if($x) { + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($url) + ); + if($r) { + + $photos = import_profile_photo($pphoto,$url); + if($photos) { + $z = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', + xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s' limit 1", + dbesc(datetime_convert()), + dbesc($photos[0]), + dbesc($photos[1]), + dbesc($photos[2]), + dbesc($photos[3]), + dbesc($url) + ); + } + + set_xconfig($url,'system','openid',$authid); + $_SESSION['authenticated'] = 1; + $_SESSION['visitor_id'] = $r[0]['xchan_hash']; + $_SESSION['my_url'] = $r[0]['xchan_url']; + $_SESSION['my_address'] = $r[0]['xchan_addr']; + $arr = array('xchan' => $r[0], 'session' => $_SESSION); + call_hooks('magic_auth_openid_success',$arr); + $a->set_observer($r[0]); + info(sprintf( t('Welcome %s. Remote authentication successful.'),$r[0]['xchan_name'])); + logger('mod_openid: remote auth success from ' . $r[0]['xchan_addr']); + if($_SESSION['return_url']) + goaway($_SESSION['return_url']); + goaway(z_root()); + } + } + + } + } + notice( t('Login failed.') . EOL); + goaway(z_root()); + // NOTREACHED +} diff --git a/mod/page.php b/mod/page.php new file mode 100644 index 000000000..b3f53a227 --- /dev/null +++ b/mod/page.php @@ -0,0 +1,117 @@ +<?php + +require_once('include/items.php'); +require_once('include/conversation.php'); +require_once('include/page_widgets.php'); + +function page_init(&$a) { + // We need this to make sure the channel theme is always loaded. + + $which = argv(1); + $profile = 0; + profile_load($a,$which,$profile); + + if($a->profile['profile_uid']) + head_set_icon($a->profile['thumb']); + +} + + + + +function page_content(&$a) { + + $observer = $a->get_observer(); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + $perms = get_all_perms($a->profile['profile_uid'],$ob_hash); + + if(! $perms['view_pages']) { + notice( t('Permission denied.') . EOL); + return; + } + + if(argc() < 3) { + notice( t('Invalid item.') . EOL); + return; + } + + $channel_address = argv(1); + $page_id = argv(2); + + $u = q("select channel_id from channel where channel_address = '%s' limit 1", + dbesc($channel_address) + ); + + if(! $u) { + notice( t('Channel not found.') . EOL); + return; + } + + if($_REQUEST['rev']) + $revision = " and revision = " . intval($_REQUEST['rev']) . " "; + else + $revision = " order by revision desc "; + + require_once('include/security.php'); + $sql_options = item_permissions_sql($u[0]['channel_id']); + + $r = q("select item.* from item left join item_id on item.id = item_id.iid + where item.uid = %d and sid = '%s' and service = 'WEBPAGE' and + item_restrict = %d $sql_options $revision limit 1", + intval($u[0]['channel_id']), + dbesc($page_id), + intval(ITEM_WEBPAGE) + ); + + if(! $r) { + + // Check again with no permissions clause to see if it is a permissions issue + + $x = q("select item.* from item left join item_id on item.id = item_id.iid + where item.uid = %d and sid = '%s' and service = 'WEBPAGE' and + item_restrict = %d $revision limit 1", + intval($u[0]['channel_id']), + dbesc($page_id), + intval(ITEM_WEBPAGE) + ); + if($x) { + // Yes, it's there. You just aren't allowed to see it. + notice( t('Permission denied.') . EOL); + } + else { + notice( t('Page not found.') . EOL); + } + return; + } + + if($r[0]['layout_mid']) { + $l = q("select body from item where mid = '%s' and uid = %d limit 1", + dbesc($r[0]['layout_mid']), + intval($u[0]['channel_id']) + ); + + if($l) { + require_once('include/comanche.php'); + comanche_parser(get_app(),$l[0]['body']); + } + } + + + // logger('layout: ' . print_r($a->layout,true)); + + // Use of widgets should be determined by Comanche, but we don't have it on system pages yet, so... + + if ($perms['write_pages']) { + $chan = $a->channel['channel_id']; + $who = $channel_address; + $which = $r[0]['id']; + $o .= writepages_widget($who,$which); + } + + xchan_query($r); + $r = fetch_post_tags($r,true); + $o .= prepare_page($r[0]); + return $o; + +} diff --git a/mod/parse_url.php b/mod/parse_url.php index 600d3dc8b..340e1a67e 100644 --- a/mod/parse_url.php +++ b/mod/parse_url.php @@ -55,34 +55,18 @@ function completeurl($url, $scheme) { function parseurl_getsiteinfo($url) { $siteinfo = array(); - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_HEADER, 1); - curl_setopt($ch, CURLOPT_NOBODY, 0); - curl_setopt($ch, CURLOPT_TIMEOUT, 3); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch,CURLOPT_USERAGENT,'Opera/9.64(Windows NT 5.1; U; de) Presto/2.1.1'); - - $header = curl_exec($ch); - curl_close($ch); - - // Fetch the first mentioned charset. Can be in body or header - if (preg_match('/charset=(.*?)['."'".'"\s\n]/', $header, $matches)) - $charset = trim(array_pop($matches)); - else - $charset = "utf-8"; - $pos = strpos($header, "\r\n\r\n"); + $result = z_fetch_url($url,false,0,array('novalidate' => true)); + if(! $result['success']) + return $siteinfo; - if ($pos) - $body = trim(substr($header, $pos)); - else - $body = $header; + $header = $result['header']; + $body = $result['body']; - $body = mb_convert_encoding($body, "UTF-8", $charset); - $body = mb_convert_encoding($body, 'HTML-ENTITIES', "UTF-8"); + $body = mb_convert_encoding($body, 'UTF-8', 'UTF-8'); + $body = mb_convert_encoding($body, 'HTML-ENTITIES', "UTF-8"); - $doc = new DOMDocument(); + $doc = new DOMDocument(); @$doc->loadHTML($body); deletenode($doc, 'style'); @@ -115,6 +99,9 @@ function parseurl_getsiteinfo($url) { $attr["content"] = html_entity_decode($attr["content"], ENT_QUOTES, "UTF-8"); switch (strtolower($attr["name"])) { + case 'generator': + $siteinfo['generator'] = $attr['content']; + break; case "fulltitle": $siteinfo["title"] = $attr["content"]; break; @@ -245,6 +232,10 @@ function parse_url_content(&$a) { else $url = trim($_GET['url']); + if((substr($url,0,1) != '/') && (substr($url,0,4) != 'http')) + $url = 'http://' . $url; + + if($_GET['title']) $title = strip_tags(trim($_GET['title'])); @@ -261,7 +252,7 @@ function parse_url_content(&$a) { logger('parse_url: ' . $url); - $template = $br . '[url=%s]%s[/url]%s' . $br; + $template = $br . '#^[url=%s]%s[/url]%s' . $br; $arr = array('url' => $url, 'text' => ''); @@ -290,6 +281,11 @@ function parse_url_content(&$a) { $siteinfo = parseurl_getsiteinfo($url); + // If this is a Red site, use zrl rather than url so they get zids sent to them by default + + if( x($siteinfo,'generator') && (strpos($siteinfo['generator'],RED_PLATFORM . ' ') === 0)) + $template = str_replace('url','zrl',$template); + if($siteinfo["title"] == "") { echo sprintf($template,$url,$url,'') . $str_tags; killme(); diff --git a/mod/pdledit.php b/mod/pdledit.php new file mode 100644 index 000000000..36b9a0c14 --- /dev/null +++ b/mod/pdledit.php @@ -0,0 +1,62 @@ +<?php + +function pdledit_post(&$a) { + if(! local_user()) + return; + if(! $_REQUEST['module']) + return; + if(! trim($_REQUEST['content'])) { + del_pconfig(local_user(),'system','mod_' . $_REQUEST['module'] . '.pdl'); + goaway(z_root() . '/pdledit/' . $_REQUEST['module']); + } + set_pconfig(local_user(),'system','mod_' . $_REQUEST['module'] . '.pdl',escape_tags($_REQUEST['content'])); + info( t('Layout updated.') . EOL); + goaway(z_root() . '/pdledit/' . $_REQUEST['module']); +} + + +function pdledit_content(&$a) { + + if(! local_user()) { + notice( t('Permission denied.') . EOL); + return; + } + + if(argc() > 1) + $module = 'mod_' . argv(1) . '.pdl'; + else { + $o .= '<h1>' . t('Edit System Page Description') . '</h1>'; + $files = glob('mod/*'); + if($files) { + foreach($files as $f) { + $name = basename($f,'.php'); + $x = theme_include('mod_' . $name . '.pdl'); + if($x) { + $o .= '<a href="pdledit/' . $name . '" >' . $name . '</a><br />'; + } + } + } + + // list module pdl files + return $o; + } + + $t = get_pconfig(local_user(),'system',$module); + if(! $t) + $t = file_get_contents(theme_include($module)); + if(! $t) { + notice( t('Layout not found.') . EOL); + return ''; + } + + $o = replace_macros(get_markup_template('pdledit.tpl'),array( + '$header' => t('Edit System Page Description'), + '$mname' => t('Module Name:'), + '$help' => t('Layout Help'), + '$module' => argv(1), + '$content' => htmlspecialchars($t,ENT_COMPAT,'UTF-8'), + '$submit' => t('Submit') + )); + + return $o; +} diff --git a/mod/photo.php b/mod/photo.php index 5033033ff..9302278b6 100644 --- a/mod/photo.php +++ b/mod/photo.php @@ -1,7 +1,7 @@ <?php require_once('include/security.php'); -require_once('include/Photo.php'); +require_once('include/photo/photo_driver.php'); function photo_init(&$a) { @@ -22,13 +22,23 @@ function photo_init(&$a) { // NOTREACHED } - $default = 'images/person-175.jpg'; + if($photo === 'qr') { + $t = $_GET['qr']; + require_once('library/phpqrcode/phpqrcode.php'); + header("Content-type: image/png"); + QRcode::png(($t) ? $t : '.'); + killme(); + } - if(isset($type)) { + $observer_xchan = get_observer_hash(); + $default = get_default_profile_photo(); + + if(isset($type)) { /** - * Profile photos + * Profile photos - Access controls on default profile photos are not honoured since they need to be exchanged with remote sites. + * */ if($type === 'profile') { @@ -36,11 +46,11 @@ function photo_init(&$a) { case 'm': $resolution = 5; - $default = 'images/person-80.jpg'; + $default = get_default_profile_photo(80); break; case 's': $resolution = 6; - $default = 'images/person-48.jpg'; + $default = get_default_profile_photo(48); break; case 'l': default: @@ -70,6 +80,22 @@ function photo_init(&$a) { * Other photos */ + /* Check for a cookie to indicate display pixel density, in order to detect high-resolution + displays. This procedure was derived from the "Retina Images" by Jeremey Worboys, + used in accordance with the Creative Commons Attribution 3.0 Unported License. + Project link: https://github.com/Retina-Images/Retina-Images + License link: http://creativecommons.org/licenses/by/3.0/ + */ + $cookie_value = false; + if (isset($_COOKIE['devicePixelRatio'])) { + $cookie_value = intval($_COOKIE['devicePixelRatio']); + } + else { + // Force revalidation of cache on next request + $cache_directive = 'no-cache'; + $status = 'no cookie'; + } + $resolution = 0; if(strpos($photo,'.') !== false) @@ -78,14 +104,32 @@ function photo_init(&$a) { if(substr($photo,-2,1) == '-') { $resolution = intval(substr($photo,-1,1)); $photo = substr($photo,0,-2); + // If viewing on a high-res screen, attempt to serve a higher resolution image: + if ($resolution == 2 && ($cookie_value > 1)) + { + $resolution = 1; + } } + + // If using resolution 1, make sure it exists before proceeding: + if ($resolution == 1) + { + $r = q("SELECT uid FROM photo WHERE resource_id = '%s' AND scale = %d LIMIT 1", + dbesc($photo), + intval($resolution) + ); + if (!($r)) + $resolution = 2; + } $r = q("SELECT uid FROM photo WHERE resource_id = '%s' AND scale = %d LIMIT 1", dbesc($photo), intval($resolution) ); - if(count($r)) { + if($r) { + $allowed = (($r[0]['uid']) ? perm_is_allowed($r[0]['uid'],$observer_xchan,'view_photos') : true); + $sql_extra = permissions_sql($r[0]['uid']); // Now we'll see if we can access the photo @@ -95,7 +139,7 @@ function photo_init(&$a) { intval($resolution) ); - if(count($r)) { + if($r && $allowed) { $data = $r[0]['data']; $mimetype = $r[0]['type']; } @@ -108,14 +152,18 @@ function photo_init(&$a) { // There won't be many completely unauthorised people seeing this because // they won't have the photo link, so there's a reasonable chance that the person // might be able to obtain permission to view it. - + $r = q("SELECT * FROM `photo` WHERE `resource_id` = '%s' AND `scale` = %d LIMIT 1", dbesc($photo), intval($resolution) ); - if(count($r)) { - $data = file_get_contents('images/nosign.jpg'); - $mimetype = 'image/jpeg'; + + if($r) { + logger('mod_photo: forbidden. ' . $a->query_string); + $observer = $a->get_observer(); + logger('mod_photo: observer = ' . (($observer) ? $observer['xchan_addr'] : '(not authenticated)')); + $data = file_get_contents('images/nosign.png'); + $mimetype = 'image/png'; $prvcachecontrol = true; } } @@ -127,15 +175,15 @@ function photo_init(&$a) { switch($resolution) { case 4: - $data = file_get_contents('images/person-175.jpg'); + $data = file_get_contents(get_default_profile_photo()); $mimetype = 'image/jpeg'; break; case 5: - $data = file_get_contents('images/person-80.jpg'); + $data = file_get_contents(get_default_profile_photo(80)); $mimetype = 'image/jpeg'; break; case 6: - $data = file_get_contents('images/person-48.jpg'); + $data = file_get_contents(get_default_profile_photo(48)); $mimetype = 'image/jpeg'; break; default: @@ -147,7 +195,7 @@ function photo_init(&$a) { } if(isset($res) && intval($res) && $res < 500) { - $ph = new Photo($data, $mimetype); + $ph = photo_factory($data, $mimetype); if($ph->is_valid()) { $ph->scaleImageSquare($res); $data = $ph->imageString(); diff --git a/mod/photos.php b/mod/photos.php index ee0a930fd..c43beb8d4 100644 --- a/mod/photos.php +++ b/mod/photos.php @@ -1,9 +1,11 @@ <?php -require_once('include/Photo.php'); +require_once('include/photo/photo_driver.php'); +require_once('include/photos.php'); require_once('include/items.php'); require_once('include/acl_selectors.php'); require_once('include/bbcode.php'); require_once('include/security.php'); +require_once('include/Contact.php'); function photos_init(&$a) { @@ -12,91 +14,30 @@ function photos_init(&$a) { if((get_config('system','block_public')) && (! local_user()) && (! remote_user())) { return; } + $o = ''; if(argc() > 1) { $nick = argv(1); - $r = q("SELECT * FROM channel WHERE channel_address = '%s' LIMIT 1", - dbesc($nick) - ); - - if(! $r) - return; - - $a->data['channel'] = $r[0]; - $observer = $a->get_observer(); - $a->data['perms'] = get_all_perms($r[0]['channel_id'],(($observer) ? $observer['xchan_hash'] : '')); - - $o .= '<div class="vcard">'; - $o .= '<div class="fn">' . $a->data['channel']['channel_name'] . '</div>'; - $o .= '<div id="profile-photo-wrapper"><img class="photo" style="width: 175px; height: 175px;" src="' . $a->get_cached_avatar_image($a->get_baseurl() . '/photo/profile/l/' . $a->data['channel']['channel_id']) . '" alt="' . $a->data['channel']['channel_name'] . '" /></div>'; - $o .= '</div>'; - - - $sql_extra = permissions_sql($a->data['channel']['channel_id']); - - $albums = q("SELECT distinct(`album`) AS `album` FROM `photo` WHERE `uid` = %d $sql_extra order by created desc", - intval($a->data['channel']['channel_id']) - ); - - if(count($albums)) { - $a->data['albums'] = $albums; -// FIXME - $albums_visible = ((intval($a->data['user']['hidewall']) && (! local_user()) && (! remote_user())) ? false : true); - - if($albums_visible) { - $o .= '<div id="side-bar-photos-albums" class="widget">'; - $o .= '<h3>' . '<a href="' . $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '">' . t('Photo Albums') . '</a></h3>'; - - $o .= '<ul>'; - foreach($albums as $album) { - - // don't show contact photos. We once translated this name, but then you could still access it under - // a different language setting. Now we store the name in English and check in English (and translated for legacy albums). - - if((! strlen($album['album'])) || ($album['album'] === 'Contact Photos') || ($album['album'] === t('Contact Photos'))) - continue; - $o .= '<li>' . '<a href="photos/' . $a->argv[1] . '/album/' . bin2hex($album['album']) . '" >' . $album['album'] . '</a></li>'; - } - $o .= '</ul>'; - } - if(local_user() && $a->data['channel']['channel_id'] == local_user()) { - $o .= '<div id="photo-albums-upload-link"><a href="' . $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/upload" >' .t('Upload New Photos') . '</a></div>'; - } - - $o .= '</div>'; - } + profile_load($a,$nick); - if(! x($a->page,'aside')) - $a->page['aside'] = ''; - $a->page['aside'] .= $o; + $channelx = channelx_by_nick($nick); + if(! $channelx) + return; - $a->page['htmlhead'] .= "<script> var ispublic = '" . t('everybody') . "';" ; + $a->data['channel'] = $channelx; - $a->page['htmlhead'] .= <<< EOT + $observer = $a->get_observer(); + $a->data['observer'] = $observer; - $(document).ready(function() { + $observer_xchan = (($observer) ? $observer['xchan_hash'] : ''); - $('#contact_allow, #contact_deny, #group_allow, #group_deny').change(function() { - var selstr; - $('#contact_allow option:selected, #contact_deny option:selected, #group_allow option:selected, #group_deny option:selected').each( function() { - selstr = $(this).text(); - $('#jot-perms-icon').removeClass('unlock').addClass('lock'); - $('#jot-public').hide(); - }); - if(selstr == null) { - $('#jot-perms-icon').removeClass('lock').addClass('unlock'); - $('#jot-public').show(); - } + head_set_icon($a->data['channel']['xchan_photo_s']); - }).trigger('change'); + $a->page['htmlhead'] .= "<script> var ispublic = '" . t('everybody') . "'; var profile_uid = " . (($a->data['channel']) ? $a->data['channel']['channel_id'] : 0) . "; </script>" ; - }); - - </script> -EOT; } return; @@ -112,185 +53,138 @@ function photos_post(&$a) { logger('mod_photos: REQUEST ' . print_r($_REQUEST,true), LOGGER_DATA); logger('mod_photos: FILES ' . print_r($_FILES,true), LOGGER_DATA); - $phototypes = Photo::supportedTypes(); + $ph = photo_factory(''); + + $phototypes = $ph->supportedTypes(); $can_post = false; - $visitor = 0; $page_owner_uid = $a->data['channel']['channel_id']; - $community_page = (($a->data['user']['page-flags'] == PAGE_COMMUNITY) ? true : false); - if((local_user()) && (local_user() == $page_owner_uid)) + if(perm_is_allowed($page_owner_uid,get_observer_hash(),'post_photos')) $can_post = true; - else { - if($community_page && remote_user()) { - $cid = 0; - if(is_array($_SESSION['remote'])) { - foreach($_SESSION['remote'] as $v) { - if($v['uid'] == $page_owner_uid) { - $cid = $v['cid']; - break; - } - } - } - if($cid) { - - $r = q("SELECT `uid` FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `id` = %d AND `uid` = %d LIMIT 1", - intval($cid), - intval($page_owner_uid) - ); - if(count($r)) { - $can_post = true; - $visitor = $cid; - } - } - } - } if(! $can_post) { notice( t('Permission denied.') . EOL ); - killme(); + if(is_ajax()) + killme(); + return; } - $r = q("SELECT `contact`.*, `user`.`nickname` FROM `contact` LEFT JOIN `user` ON `user`.`uid` = `contact`.`uid` - WHERE `user`.`uid` = %d AND `self` = 1 LIMIT 1", - intval($page_owner_uid) - ); + $s = abook_self($page_owner_uid); - if(! count($r)) { - notice( t('Contact information unavailable') . EOL); - logger('photos_post: unable to locate contact record for page owner. uid=' . $page_owner_uid); - killme(); + if(! $s) { + notice( t('Page owner information could not be retrieved.') . EOL); + logger('mod_photos: post: unable to locate contact record for page owner. uid=' . $page_owner_uid); + if(is_ajax()) + killme(); + return; } - $owner_record = $r[0]; + $owner_record = $s[0]; - if(($a->argc > 3) && ($a->argv[2] === 'album')) { - $album = hex2bin($a->argv[3]); + if((argc() > 3) && (argv(2) === 'album')) { - if($album === t('Profile Photos') || $album === 'Contact Photos' || $album === t('Contact Photos')) { + $album = hex2bin(argv(3)); + + if($album === t('Profile Photos')) { + // not allowed goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); - return; // NOTREACHED } - $r = q("SELECT count(*) FROM `photo` WHERE `album` = '%s' AND `uid` = %d", - dbesc($album), - intval($page_owner_uid) - ); - if(! count($r)) { + if(! photos_album_exists($page_owner_uid,$album)) { notice( t('Album not found.') . EOL); goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); - return; // NOTREACHED } - $newalbum = notags(trim($_POST['albumname'])); + + /* + * RENAME photo album + */ + + $newalbum = notags(trim($_REQUEST['albumname'])); if($newalbum != $album) { - q("UPDATE `photo` SET `album` = '%s' WHERE `album` = '%s' AND `uid` = %d", - dbesc($newalbum), - dbesc($album), - intval($page_owner_uid) - ); - $newurl = str_replace(bin2hex($album),bin2hex($newalbum),$_SESSION['photo_return']); - goaway($a->get_baseurl() . '/' . $newurl); - return; // NOTREACHED + $x = photos_album_rename($page_owner_uid,$album,$newalbum); + if($x) { + $newurl = str_replace(bin2hex($album),bin2hex($newalbum),$_SESSION['photo_return']); + goaway($a->get_baseurl() . '/' . $newurl); + } } + /* + * DELETE photo album and all its photos + */ - if($_POST['dropalbum'] == t('Delete Album')) { + if($_REQUEST['dropalbum'] == t('Delete Album')) { $res = array(); // get the list of photos we are about to delete - if($visitor) { - $r = q("SELECT distinct(`resource_id`) as `rid` FROM `photo` WHERE `contact-id` = %d AND `uid` = %d AND `album` = '%s'", - intval($visitor), - intval($page_owner_uid), - dbesc($album) - ); - } - else { - $r = q("SELECT distinct(`resource_id`) as `rid` FROM `photo` WHERE `uid` = %d AND `album` = '%s'", - intval(local_user()), - dbesc($album) - ); + if(remote_user() && (! local_user())) { + $str = photos_album_get_db_idstr($page_owner_uid,$album,remote_user()); } - if(count($r)) { - foreach($r as $rr) { - $res[] = "'" . dbesc($rr['rid']) . "'" ; - } + elseif(local_user()) { + $str = photos_album_get_db_idstr(local_user(),$album); } else { + $str = null; + } + if(! $str) { goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); - return; // NOTREACHED } - $str_res = implode(',', $res); - - // remove the associated photos - - q("DELETE FROM `photo` WHERE `resource_id` IN ( $str_res ) AND `uid` = %d", + $r = q("select id, item_restrict from item where resource_id in ( $str ) and resource_type = 'photo' and uid = %d", intval($page_owner_uid) ); + if($r) { + foreach($r as $i) { + drop_item($i['id'],false); + if(! $item_restrict) + proc_run('php','include/notifier.php','drop',$i['id']); + } + } - // find and delete the corresponding item with all the comments and likes/dislikes + // remove the associated photos in case they weren't attached to an item - $r = q("SELECT `parent_uri` FROM `item` WHERE `resource_id` IN ( $str_res ) AND `uid` = %d", + q("delete from photo where resource_id in ( $str ) and uid = %d", intval($page_owner_uid) ); - if(count($r)) { - foreach($r as $rr) { - q("UPDATE `item` SET `deleted` = 1, `changed` = '%s' WHERE `parent_uri` = '%s' AND `uid` = %d", - dbesc(datetime_convert()), - dbesc($rr['parent_uri']), - intval($page_owner_uid) - ); - - $drop_id = intval($rr['id']); - - // send the notification upstream/downstream as the case may be - - if($rr['visible']) - proc_run('php',"include/notifier.php","drop","$drop_id"); - } - } } + goaway($a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address']); - return; // NOTREACHED } - if(($a->argc > 2) && (x($_POST,'delete')) && ($_POST['delete'] == t('Delete Photo'))) { + if((argc() > 2) && (x($_REQUEST,'delete')) && ($_REQUEST['delete'] === t('Delete Photo'))) { // same as above but remove single photo - if($visitor) { - $r = q("SELECT `id`, `resource_id` FROM `photo` WHERE `contact-id` = %d AND `uid` = %d AND `resource_id` = '%s' LIMIT 1", - intval($visitor), - intval($page_owner_uid), - dbesc($a->argv[2]) - ); - } - else { - $r = q("SELECT `id`, `resource_id` FROM `photo` WHERE `uid` = %d AND `resource_id` = '%s' LIMIT 1", - intval(local_user()), - dbesc($a->argv[2]) - ); - } - if(count($r)) { + $ob_hash = get_observer_hash(); + if(! $ob_hash) + goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); + + $r = q("SELECT `id`, `resource_id` FROM `photo` WHERE ( xchan = '%s' or `uid` = %d ) AND `resource_id` = '%s' LIMIT 1", + dbesc($ob_hash), + intval(local_user()), + dbesc($a->argv[2]) + ); + + if($r) { q("DELETE FROM `photo` WHERE `uid` = %d AND `resource_id` = '%s'", intval($page_owner_uid), dbesc($r[0]['resource_id']) ); - $i = q("SELECT * FROM `item` WHERE `resource_id` = '%s' AND `uid` = %d LIMIT 1", + $i = q("SELECT * FROM `item` WHERE `resource_id` = '%s' AND resource_type = 'photo' and `uid` = %d LIMIT 1", dbesc($r[0]['resource_id']), intval($page_owner_uid) ); if(count($i)) { - q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s' WHERE `parent_uri` = '%s' AND `uid` = %d", + q("UPDATE `item` SET item_restrict = (item_restrict | %d), `edited` = '%s', `changed` = '%s' WHERE `parent_mid` = '%s' AND `uid` = %d", + intval(ITEM_DELETED), dbesc(datetime_convert()), dbesc(datetime_convert()), - dbesc($i[0]['uri']), + dbesc($i[0]['mid']), intval($page_owner_uid) ); @@ -303,7 +197,6 @@ function photos_post(&$a) { } goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); - return; // NOTREACHED } if(($a->argc > 2) && ((x($_POST,'desc') !== false) || (x($_POST,'newtag') !== false)) || (x($_POST,'albname') !== false)) { @@ -333,7 +226,7 @@ function photos_post(&$a) { intval($page_owner_uid) ); if(count($r)) { - $ph = new Photo($r[0]['data'], $r[0]['type']); + $ph = photo_factory($r[0]['data'], $r[0]['type']); if($ph->is_valid()) { $rotate_deg = ( (intval($_POST['rotate']) == 1) ? 270 : 90 ); $ph->rotate($rotate_deg); @@ -380,13 +273,16 @@ function photos_post(&$a) { } } - $p = q("SELECT * FROM `photo` WHERE `resource_id` = '%s' AND `uid` = %d ORDER BY `scale` DESC", + $p = q("SELECT * FROM `photo` WHERE `resource_id` = '%s' AND `uid` = %d and ( photo_flags = %d or photo_flags = %d ) ORDER BY `scale` DESC", dbesc($resource_id), - intval($page_owner_uid) + intval($page_owner_uid), + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE) ); if(count($p)) { $ext = $phototypes[$p[0]['type']]; - $r = q("UPDATE `photo` SET `desc` = '%s', `album` = '%s', `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s' WHERE `resource_id` = '%s' AND `uid` = %d", + + $r = q("UPDATE `photo` SET `description` = '%s', `album` = '%s', `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s' WHERE `resource_id` = '%s' AND `uid` = %d", dbesc($desc), dbesc($albname), dbesc($str_contact_allow), @@ -398,48 +294,17 @@ function photos_post(&$a) { ); } + $item_private = (($str_contact_allow || $str_group_allow || $str_contact_deny || $str_group_deny) ? true : false); + + /* Don't make the item visible if the only change was the album name */ $visibility = 0; - if($p[0]['desc'] !== $desc || strlen($rawtags)) + if($p[0]['description'] !== $desc || strlen($rawtags)) $visibility = 1; if(! $item_id) { - - // Create item container - - $item_flags = ITEM_WALL|ITEM_ORIGIN|ITEM_THREAD_TOP; - $item_restrict = (($visibility) ? ITEM_HIDDEN : ITEM_VISIBLE); - - $title = ''; - $uri = item_message_id(); - - $arr = array(); - - $arr['aid'] = $a->data['channel']['channel_account_id']; - $arr['uid'] = $page_owner_uid; - $arr['uri'] = $uri; - $arr['parent_uri'] = $uri; - $arr['item_flags'] = $item_flags; - $arr['item_restrict'] = $item_restrict; - $arr['resource_type'] = 'photo'; - $arr['resource_id'] = $p[0]['resource_id']; - $arr['owner_xchan'] = $a->data['channel']['channel_hash']; - $arr['author_xchan'] = $a->data['channel']['channel_hash']; // FIXME for AUTH guests - - $arr['title'] = $title; - $arr['allow_cid'] = $p[0]['allow_cid']; - $arr['allow_gid'] = $p[0]['allow_gid']; - $arr['deny_cid'] = $p[0]['deny_cid']; - $arr['deny_gid'] = $p[0]['deny_gid']; - - - - $arr['body'] = '[url=' . $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/image/' . $p[0]['resource_id'] . ']' - . '[img]' . $a->get_baseurl() . '/photo/' . $p[0]['resource_id'] . '-' . $p[0]['scale'] . '[/img]' - . '[/url]'; - - $item_id = item_store($arr); + $item_id = photos_create_item($a->data['channel'],get_observer_hash(),$p[0],$visibility); } @@ -449,209 +314,99 @@ function photos_post(&$a) { intval($page_owner_uid) ); } - if(count($r)) { + if($r) { $old_tag = $r[0]['tag']; $old_inform = $r[0]['inform']; } + // make sure the linked item has the same permissions as the photo regardless of any other changes + $x = q("update item set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', item_private = %d + where id = %d limit 1", + dbesc($str_contact_allow), + dbesc($str_group_allow), + dbesc($str_contact_deny), + dbesc($str_group_deny), + intval($item_private), + intval($item_id) + ); + + if(strlen($rawtags)) { $str_tags = ''; $inform = ''; - // if the new tag doesn't have a namespace specifier (@foo or #foo) give it a hashtag + // if the new tag doesn't have a namespace specifier (@foo or #foo) give it a mention $x = substr($rawtags,0,1); if($x !== '@' && $x !== '#') - $rawtags = '#' . $rawtags; + $rawtags = '@' . $rawtags; $taginfo = array(); $tags = get_tags($rawtags); if(count($tags)) { foreach($tags as $tag) { - if(isset($profile)) - unset($profile); - if(strpos($tag,'@') === 0) { - $name = substr($tag,1); - if((strpos($name,'@')) || (strpos($name,'http://'))) { - $newname = $name; - $links = @lrdd($name); - if(count($links)) { - foreach($links as $link) { - if($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page') - $profile = $link['@attributes']['href']; - if($link['@attributes']['rel'] === 'salmon') { - $salmon = '$url:' . str_replace(',','%sc',$link['@attributes']['href']); - if(strlen($inform)) - $inform .= ','; - $inform .= $salmon; - } - } - } - $taginfo[] = array($newname,$profile,$salmon); + + // If we already tagged 'Robert Johnson', don't try and tag 'Robert'. + // Robert Johnson should be first in the $tags array + + $fullnametagged = false; + for($x = 0; $x < count($tagged); $x ++) { + if(stristr($tagged[$x],$tag . ' ')) { + $fullnametagged = true; + break; } - else { - $newname = $name; - $alias = ''; - $tagcid = 0; - if(strrpos($newname,'+')) - $tagcid = intval(substr($newname,strrpos($newname,'+') + 1)); - - if($tagcid) { - $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($tagcid), - intval($profile_uid) - ); - } - else { - $newname = str_replace('_',' ',$name); - - //select someone from this user's contacts by name - $r = q("SELECT * FROM `contact` WHERE `name` = '%s' AND `uid` = %d LIMIT 1", - dbesc($newname), - intval($page_owner_uid) - ); - - if(! $r) { - //select someone by attag or nick and the name passed in - $r = q("SELECT * FROM `contact` WHERE `attag` = '%s' OR `nick` = '%s' AND `uid` = %d ORDER BY `attag` DESC LIMIT 1", - dbesc($name), - dbesc($name), - intval($page_owner_uid) - ); - } - } -/* elseif(strstr($name,'_') || strstr($name,' ')) { - $newname = str_replace('_',' ',$name); - $r = q("SELECT * FROM `contact` WHERE `name` = '%s' AND `uid` = %d LIMIT 1", - dbesc($newname), - intval($page_owner_uid) - ); - } - else { - $r = q("SELECT * FROM `contact` WHERE `attag` = '%s' OR `nick` = '%s' AND `uid` = %d ORDER BY `attag` DESC LIMIT 1", - dbesc($name), - dbesc($name), - intval($page_owner_uid) - ); - }*/ - if(count($r)) { - $newname = $r[0]['name']; - $profile = $r[0]['url']; - $notify = 'cid:' . $r[0]['id']; - if(strlen($inform)) - $inform .= ','; - $inform .= $notify; - } + } + if($fullnametagged) + continue; + + require_once('mod/item.php'); + $body = $access_tag = ''; + + $success = handle_tag($a, $body, $access_tag, $str_tags, (local_user()) ? local_user() : $a->profile['profile_uid'] , $tag); + logger('handle_tag: ' . print_r($success,tue), LOGGER_DEBUG); + if($access_tag) { + logger('access_tag: ' . $tag . ' ' . print_r($access_tag,true), LOGGER_DEBUG); + if(strpos($access_tag,'cid:') === 0) { + $str_contact_allow .= '<' . substr($access_tag,4) . '>'; + $access_tag = ''; } - if($profile) { - if(substr($notify,0,4) === 'cid:') - $taginfo[] = array($newname,$profile,$notify,$r[0],'@[url=' . str_replace(',','%2c',$profile) . ']' . $newname . '[/url]'); - else - $taginfo[] = array($newname,$profile,$notify,null,$str_tags .= '@[url=' . $profile . ']' . $newname . '[/url]'); - if(strlen($str_tags)) - $str_tags .= ','; - $profile = str_replace(',','%2c',$profile); - $str_tags .= '@[url=' . $profile . ']' . $newname . '[/url]'; + elseif(strpos($access_tag,'gid:') === 0) { + $str_group_allow .= '<' . substr($access_tag,4) . '>'; + $access_tag = ''; } } + + if($success['replaced']) { + $tagged[] = $tag; + $post_tags[] = array( + 'uid' => $a->profile['profile_uid'], + 'type' => $success['termtype'], + 'otype' => TERM_OBJ_POST, + 'term' => $success['term'], + 'url' => $success['url'] + ); + } } } - - $newtag = $old_tag; - if(strlen($newtag) && strlen($str_tags)) - $newtag .= ','; - $newtag .= $str_tags; - - $newinform = $old_inform; - if(strlen($newinform) && strlen($inform)) - $newinform .= ','; - $newinform .= $inform; - - $r = q("UPDATE `item` SET `tag` = '%s', `inform` = '%s', `edited` = '%s', `changed` = '%s' WHERE `id` = %d AND `uid` = %d LIMIT 1", - dbesc($newtag), - dbesc($newinform), - dbesc(datetime_convert()), - dbesc(datetime_convert()), + + $r = q("select * from item where id = %d and uid = %d limit 1", intval($item_id), intval($page_owner_uid) ); - $best = 0; - foreach($p as $scales) { - if(intval($scales['scale']) == 2) { - $best = 2; - break; - } - if(intval($scales['scale']) == 4) { - $best = 4; - break; - } - } - - if(count($taginfo)) { - foreach($taginfo as $tagged) { - - $uri = item_message_id(); - - $arr = array(); - - $arr['uid'] = $page_owner_uid; - $arr['uri'] = $uri; - $arr['parent_uri'] = $uri; - $arr['type'] = 'activity'; - $arr['wall'] = 1; - $arr['contact-id'] = $owner_record['id']; - $arr['owner-name'] = $owner_record['name']; - $arr['owner-link'] = $owner_record['url']; - $arr['owner-avatar'] = $owner_record['thumb']; - $arr['author-name'] = $owner_record['name']; - $arr['author-link'] = $owner_record['url']; - $arr['author-avatar'] = $owner_record['thumb']; - $arr['title'] = ''; - $arr['allow_cid'] = $p[0]['allow_cid']; - $arr['allow_gid'] = $p[0]['allow_gid']; - $arr['deny_cid'] = $p[0]['deny_cid']; - $arr['deny_gid'] = $p[0]['deny_gid']; - $arr['visible'] = 1; - $arr['verb'] = ACTIVITY_TAG; - $arr['obj_type'] = ACTIVITY_OBJ_PERSON; - $arr['tgt_type'] = ACTIVITY_OBJ_PHOTO; - $arr['tag'] = $tagged[4]; - $arr['inform'] = $tagged[2]; - $arr['origin'] = 1; - $arr['body'] = sprintf( t('%1$s was tagged in %2$s by %3$s'), '[url=' . $tagged[1] . ']' . $tagged[0] . '[/url]', '[url=' . $a->get_baseurl() . '/photos/' . $owner_record['nickname'] . '/image/' . $p[0]['resource-id'] . ']' . t('a photo') . '[/url]', '[url=' . $owner_record['url'] . ']' . $owner_record['name'] . '[/url]') ; - - $arr['body'] .= "\n\n" . '[url=' . $a->get_baseurl() . '/photos/' . $owner_record['nickname'] . '/image/' . $p[0]['resource_id'] . ']' . '[img]' . $a->get_baseurl() . "/photo/" . $p[0]['resource_id'] . '-' . $best . '.' . $ext . '[/img][/url]' . "\n" ; - - $arr['object'] = '<object><type>' . ACTIVITY_OBJ_PERSON . '</type><title>' . $tagged[0] . '</title><id>' . $tagged[1] . '/' . $tagged[0] . '</id>'; - $arr['object'] .= '<link>' . xmlify('<link rel="alternate" type="text/html" href="' . $tagged[1] . '" />' . "\n"); - if($tagged[3]) - $arr['object'] .= xmlify('<link rel="photo" type="'.$p[0]['type'].'" href="' . $tagged[3]['photo'] . '" />' . "\n"); - $arr['object'] .= '</link></object>' . "\n"; - - $arr['target'] = '<target><type>' . ACTIVITY_OBJ_PHOTO . '</type><title>' . $p[0]['desc'] . '</title><id>' - . $a->get_baseurl() . '/photos/' . $owner_record['nickname'] . '/image/' . $p[0]['resource_id'] . '</id>'; - $arr['target'] .= '<link>' . xmlify('<link rel="alternate" type="text/html" href="' . $a->get_baseurl() . '/photos/' . $owner_record['nickname'] . '/image/' . $p[0]['resource_id'] . '" />' . "\n" . '<link rel="preview" type="'.$p[0]['type'].'" href="' . $a->get_baseurl() . "/photo/" . $p[0]['resource_id'] . '-' . $best . '.' . $ext . '" />') . '</link></target>'; - - $item_id = item_store($arr); - if($item_id) { - q("UPDATE `item` SET `plink` = '%s' WHERE `uid` = %d AND `id` = %d LIMIT 1", - dbesc($a->get_baseurl() . '/display/' . $owner_record['nickname'] . '/' . $item_id), - intval($page_owner_uid), - intval($item_id) - ); - - proc_run('php',"include/notifier.php","tag","$item_id"); - } - } - + if($r) { + $datarray = $r[0]; + $datarray['term'] = $post_tags; + item_store_update($datarray,$execflag); } } + goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); return; // NOTREACHED + } @@ -659,211 +414,15 @@ function photos_post(&$a) { * default post action - upload a photo */ - call_hooks('photo_post_init', $_POST); - - /** - * Determine the album to use - */ - - $album = notags(trim($_REQUEST['album'])); - $newalbum = notags(trim($_REQUEST['newalbum'])); - - logger('mod/photos.php: photos_post(): album= ' . $album . ' newalbum= ' . $newalbum , LOGGER_DEBUG); - - if(! strlen($album)) { - if(strlen($newalbum)) - $album = $newalbum; - else - $album = datetime_convert('UTC',date_default_timezone_get(),'now', 'Y'); - } - - /** - * - * We create a wall item for every photo, but we don't want to - * overwhelm the data stream with a hundred newly uploaded photos. - * So we will make the first photo uploaded to this album in the last several hours - * visible by default, the rest will become visible over time when and if - * they acquire comments, likes, dislikes, and/or tags - * - */ - - $r = q("SELECT * FROM `photo` WHERE `album` = '%s' AND `uid` = %d AND `created` > UTC_TIMESTAMP() - INTERVAL 3 HOUR ", - dbesc($album), - intval($page_owner_uid) - ); - if((! count($r)) || ($album == t('Profile Photos'))) - $visible = 1; - else - $visible = 0; - - if(intval($_REQUEST['not_visible']) || $_REQUEST['not_visible'] === 'true') - $visible = 0; - - $str_group_allow = perms2str(((is_array($_REQUEST['group_allow'])) ? $_REQUEST['group_allow'] : explode(',',$_REQUEST['group_allow']))); - $str_contact_allow = perms2str(((is_array($_REQUEST['contact_allow'])) ? $_REQUEST['contact_allow'] : explode(',',$_REQUEST['contact_allow']))); - $str_group_deny = perms2str(((is_array($_REQUEST['group_deny'])) ? $_REQUEST['group_deny'] : explode(',',$_REQUEST['group_deny']))); - $str_contact_deny = perms2str(((is_array($_REQUEST['contact_deny'])) ? $_REQUEST['contact_deny'] : explode(',',$_REQUEST['contact_deny']))); - - $ret = array('src' => '', 'filename' => '', 'filesize' => 0, 'type' => ''); - - call_hooks('photo_post_file',$ret); - - if(x($ret,'src') && x($ret,'filesize')) { - $src = $ret['src']; - $filename = $ret['filename']; - $filesize = $ret['filesize']; - $type = $ret['type']; - } - else { - $src = $_FILES['userfile']['tmp_name']; - $filename = basename($_FILES['userfile']['name']); - $filesize = intval($_FILES['userfile']['size']); - $type = $_FILES['userfile']['type']; - } - if ($type=="") $type=guess_image_type($filename); - - logger('photos: upload: received file: ' . $filename . ' as ' . $src . ' ('. $type . ') ' . $filesize . ' bytes', LOGGER_DEBUG); - - $maximagesize = get_config('system','maximagesize'); - - if(($maximagesize) && ($filesize > $maximagesize)) { - notice( t('Image exceeds size limit of ') . $maximagesize . EOL); - @unlink($src); - $foo = 0; - call_hooks('photo_post_end',$foo); - return; - } - - if(! $filesize) { - notice( t('Image file is empty.') . EOL); - @unlink($src); - $foo = 0; - call_hooks('photo_post_end',$foo); - return; - } - - logger('mod/photos.php: photos_post(): loading the contents of ' . $src , LOGGER_DEBUG); - - $imagedata = @file_get_contents($src); - - - - $r = q("select sum(octet_length(data)) as total from photo where uid = %d and scale = 0 and album != 'Contact Photos' ", - intval($a->data['channel']['channel_id']) - ); - - $limit = service_class_fetch($a->data['channel']['channel_id'],'photo_upload_limit'); + $_REQUEST['source'] = 'photos'; - if(($limit !== false) && (($r[0]['total'] + strlen($imagedata)) > $limit)) { - notice( upgrade_message() . EOL ); - @unlink($src); - $foo = 0; - call_hooks('photo_post_end',$foo); - killme(); - } - - - $ph = new Photo($imagedata, $type); - - if(! $ph->is_valid()) { - logger('mod/photos.php: photos_post(): unable to process image' , LOGGER_DEBUG); - notice( t('Unable to process image.') . EOL ); - @unlink($src); - $foo = 0; - call_hooks('photo_post_end',$foo); - killme(); - } - - $ph->orient($src); - @unlink($src); - - $max_length = get_config('system','max_image_length'); - if(! $max_length) - $max_length = MAX_IMAGE_LENGTH; - if($max_length > 0) - $ph->scaleImage($max_length); - - $width = $ph->getWidth(); - $height = $ph->getHeight(); - - $smallest = 0; - - $photo_hash = photo_new_resource(); - - $r = $ph->store($page_owner_uid, $visitor, $photo_hash, $filename, $album, 0 , 0, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny); - - if(! $r) { - logger('mod/photos.php: photos_post(): image store failed' , LOGGER_DEBUG); - notice( t('Image upload failed.') . EOL ); - killme(); - } - - if($width > 640 || $height > 640) { - $ph->scaleImage(640); - $ph->store($page_owner_uid, $visitor, $photo_hash, $filename, $album, 1, 0, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny); - $smallest = 1; - } - - if($width > 320 || $height > 320) { - $ph->scaleImage(320); - $ph->store($page_owner_uid, $visitor, $photo_hash, $filename, $album, 2, 0, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny); - $smallest = 2; - } - - $basename = basename($filename); - $uri = item_message_id(); - - - // Create item container - - $item_flags = ITEM_WALL|ITEM_ORIGIN|ITEM_THREAD_TOP; - $item_restrict = (($visibility) ? ITEM_HIDDEN : ITEM_VISIBLE); - $title = ''; - $uri = item_message_id(); - - $arr = array(); - - $arr['aid'] = $a->data['channel']['channel_account_id']; - $arr['uid'] = $page_owner_uid; - $arr['uri'] = $uri; - $arr['parent_uri'] = $uri; - $arr['item_flags'] = $item_flags; - $arr['item_restrict'] = $item_restrict; - $arr['resource_type'] = 'photo'; - $arr['resource_id'] = $hoto_hash; - $arr['owner_xchan'] = $a->data['channel']['channel_hash']; - $arr['author_xchan'] = $a->data['channel']['channel_hash']; // FIXME for AUTH guests - $arr['title'] = $title; - $arr['allow_cid'] = $str_contact_allow; - $arr['allow_gid'] = $str_group_allow; - $arr['deny_cid'] = $str_contact_deny; - $arr['deny_gid'] = $str_group_deny; - - - $arr['body'] = '[url=' . $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/image/' . $photo_hash . ']' - . '[img]' . $a->get_baseurl() . "/photo/{$photo_hash}-{$smallest}.".$ph->getExt() . '[/img]' - . '[/url]'; - - $item_id = item_store($arr); - - if($item_id) { - q("UPDATE `item` SET `plink` = '%s' WHERE `uid` = %d AND `id` = %d LIMIT 1", - dbesc($a->get_baseurl() . '/display/' . $owner_record['nickname'] . '/' . $item_id), - intval($page_owner_uid), - intval($item_id) - ); - } - - if($visible) - proc_run('php', "include/notifier.php", 'wall-new', $item_id); - - call_hooks('photo_post_end',intval($item_id)); - - // addon uploaders should call "killme()" [e.g. exit] within the photo_post_end hook - // if they do not wish to be redirected + $r = photo_upload($a->channel,$a->get_observer(), $_REQUEST); + if(! $r['success']) { + notice($r['message'] . EOL); + } goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); - // NOTREACHED + } @@ -895,7 +454,8 @@ function photos_content(&$a) { return; } - $phototypes = Photo::supportedTypes(); + $ph = photo_factory(''); + $phototypes = $ph->supportedTypes(); $_SESSION['photo_return'] = $a->cmd; @@ -903,6 +463,8 @@ function photos_content(&$a) { // Parse arguments // + $can_comment = perm_is_allowed($a->profile['profile_uid'],get_observer_hash(),'post_comments'); + if(argc() > 3) { $datatype = argv(2); $datum = argv(3); @@ -923,84 +485,31 @@ function photos_content(&$a) { $can_post = false; $visitor = 0; - $contact = null; - $remote_contact = false; - $contact_id = 0; - - $owner_uid = $a->data['channel']['channel_id']; - $community_page = (($a->data['user']['page-flags'] == PAGE_COMMUNITY) ? true : false); - - if((local_user()) && (local_user() == $owner_uid)) - $can_post = true; - else { - if($community_page && remote_user()) { - if(is_array($_SESSION['remote'])) { - foreach($_SESSION['remote'] as $v) { - if($v['uid'] == $owner_uid) { - $contact_id = $v['cid']; - break; - } - } - } - if($contact_id) { - $r = q("SELECT `uid` FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `id` = %d AND `uid` = %d LIMIT 1", - intval($contact_id), - intval($owner_uid) - ); - if(count($r)) { - $can_post = true; - $contact = $r[0]; - $remote_contact = true; - $visitor = $cid; - } - } - } - } + $owner_uid = $a->data['channel']['channel_id']; + $owner_aid = $a->data['channel']['channel_account_id']; - // perhaps they're visiting - but not a community page, so they wouldn't have write access + $observer = $a->get_observer(); - if(remote_user() && (! $visitor)) { - $contact_id = 0; - if(is_array($_SESSION['remote'])) { - foreach($_SESSION['remote'] as $v) { - if($v['uid'] == $owner_uid) { - $contact_id = $v['cid']; - break; - } - } - } - if($contact_id) { - $groups = init_groups_visitor($contact_id); - $r = q("SELECT * FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `id` = %d AND `uid` = %d LIMIT 1", - intval($contact_id), - intval($owner_uid) - ); - if(count($r)) { - $contact = $r[0]; - $remote_contact = true; - } - } - } + $can_post = perm_is_allowed($owner_uid,$observer['xchan_hash'],'post_photos'); + $can_view = perm_is_allowed($owner_uid,$observer['xchan_hash'],'view_photos'); - if(! $remote_contact) { - if(local_user()) { - $contact_id = $_SESSION['cid']; - $contact = $a->contact; - } - } - if($a->data['user']['hidewall'] && (local_user() != $owner_uid) && (! $remote_contact)) { + if(! $can_view) { notice( t('Access to this item is restricted.') . EOL); return; } - $sql_extra = permissions_sql($owner_uid,$remote_contact,$groups); + $sql_extra = permissions_sql($owner_uid); $o = ""; + $o .= "<script> var profile_uid = " . $a->profile['profile_uid'] + . "; var netargs = '?f='; var profile_page = " . $a->pager['page'] . "; </script>\r\n"; + // tabs + $_is_owner = (local_user() && (local_user() == $owner_uid)); $o .= profile_tabs($a,$_is_owner, $a->data['channel']['channel_address']); @@ -1008,6 +517,9 @@ function photos_content(&$a) { // dispatch request // + /** + * Display upload form + */ if($datatype === 'upload') { if(! ($can_post)) { @@ -1016,24 +528,26 @@ function photos_content(&$a) { } - $selname = (($datum) ? hex2bin($datum) : ''); + if(array_key_exists('albums', $a->data)) + $albums = get_app()->data['albums']; + else + $albums = photos_albums_list($a->data['channel'],$a->data['observer']); - $albumselect = '<select id="photos-upload-album-select" name="album" size="4">'; + $selname = (($datum) ? hex2bin($datum) : ''); + $albumselect = '<select id="photos-upload-album-select" name="album" size="4">'; $albumselect .= '<option value="" ' . ((! $selname) ? ' selected="selected" ' : '') . '> </option>'; - if(count($a->data['albums'])) { - foreach($a->data['albums'] as $album) { - if(($album['album'] === '') || ($album['album'] === 'Contact Photos') || ($album['album'] === t('Contact Photos'))) + if(count($albums['albums'])) { + foreach($albums['albums'] as $album) { + if(! $album['text']) continue; - $selected = (($selname === $album['album']) ? ' selected="selected" ' : ''); - $albumselect .= '<option value="' . $album['album'] . '"' . $selected . '>' . $album['album'] . '</option>'; + $selected = (($selname === $album['text']) ? ' selected="selected" ' : ''); + $albumselect .= '<option value="' . $album['text'] . '"' . $selected . '>' . $album['text'] . '</option>'; } } - $celeb = ((($a->user['page-flags'] == PAGE_SOAPBOX) || ($a->user['page-flags'] == PAGE_COMMUNITY)) ? true : false); - $albumselect .= '</select>'; $uploader = ''; @@ -1048,9 +562,10 @@ function photos_content(&$a) { $default_upload = '<input id="photos-upload-choose" type="file" name="userfile" /> <div class="photos-upload-submit-wrapper" > <input type="submit" name="submit" value="' . t('Submit') . '" id="photos-upload-submit" /> </div>'; + /* Show space usage */ - $r = q("select sum(octet_length(data)) as total from photo where uid = %d and scale = 0 and album != 'Contact Photos' ", - intval($a->data['channel']['channel_id']) + $r = q("select sum(size) as total from photo where aid = %d and scale = 0 ", + intval($a->data['channel']['channel_account_id']) ); @@ -1062,6 +577,19 @@ function photos_content(&$a) { $usage_message = sprintf( t('You have used %1$.2f Mbytes of photo storage.'), $r[0]['total'] / 1024000 ); } + if($_is_owner) { + $channel = $a->get_channel(); + + $channel_acl = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + } + + $albumselect_e = $albumselect; + $aclselect_e = (($_is_owner) ? populate_acl($channel_acl,false) : ''); $tpl = get_markup_template('photos_upload.tpl'); $o .= replace_macros($tpl,array( @@ -1072,9 +600,9 @@ function photos_content(&$a) { '$newalbum' => t('New album name: '), '$existalbumtext' => t('or existing album name: '), '$nosharetext' => t('Do not show a status post for this upload'), - '$albumselect' => template_escape($albumselect), + '$albumselect' => $albumselect_e, '$permissions' => t('Permissions'), - '$aclselect' => (($visitor) ? '' : template_escape(populate_acl($a->user, $celeb))), + '$aclselect' => $aclselect_e, '$uploader' => $ret['addon_text'], '$default' => (($ret['default_upload']) ? $default_upload : ''), '$uploadurl' => $ret['post_url'] @@ -1084,18 +612,24 @@ function photos_content(&$a) { return $o; } + /* + * Display a single photo album + */ + if($datatype === 'album') { $album = hex2bin($datum); $r = q("SELECT `resource_id`, max(`scale`) AS `scale` FROM `photo` WHERE `uid` = %d AND `album` = '%s' - AND `scale` <= 4 $sql_extra GROUP BY `resource_id`", + AND `scale` <= 4 and (photo_flags = %d or photo_flags = %d ) $sql_extra GROUP BY `resource_id`", intval($owner_uid), - dbesc($album) + dbesc($album), + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE) ); if(count($r)) { $a->set_pager_total(count($r)); - $a->set_pager_itemspage(20); + $a->set_pager_itemspage(40); } if($_GET['order'] === 'posted') @@ -1103,10 +637,12 @@ function photos_content(&$a) { else $order = 'DESC'; - $r = q("SELECT `resource_id`, `id`, `filename`, type, max(`scale`) AS `scale`, `desc` FROM `photo` WHERE `uid` = %d AND `album` = '%s' - AND `scale` <= 4 $sql_extra GROUP BY `resource_id` ORDER BY `created` $order LIMIT %d , %d", + $r = q("SELECT `resource_id`, `id`, `filename`, type, max(`scale`) AS `scale`, `description` FROM `photo` WHERE `uid` = %d AND `album` = '%s' + AND `scale` <= 4 and (photo_flags = %d or photo_flags = %d ) $sql_extra GROUP BY `resource_id` ORDER BY `created` $order LIMIT %d , %d", intval($owner_uid), dbesc($album), + intvaL(PHOTO_NORMAL), + intval(PHOTO_PROFILE), intval($a->pager['start']), intval($a->pager['itemspage']) ); @@ -1116,11 +652,18 @@ function photos_content(&$a) { if($cmd === 'edit') { if(($album !== t('Profile Photos')) && ($album !== 'Contact Photos') && ($album !== t('Contact Photos'))) { if($can_post) { + if($a->get_template_engine() === 'internal') { + $album_e = template_escape($album); + } + else { + $album_e = $album; + } + $edit_tpl = get_markup_template('album_edit.tpl'); $o .= replace_macros($edit_tpl,array( '$nametext' => t('New album name: '), '$nickname' => $a->data['channel']['channel_address'], - '$album' => template_escape($album), + '$album' => $album_e, '$hexalbum' => bin2hex($album), '$submit' => t('Submit'), '$dropsubmit' => t('Delete Album') @@ -1148,11 +691,11 @@ function photos_content(&$a) { $o .= '<div class="photos-upload-link" ><a href="' . $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/upload/' . bin2hex($album) . '" >' . t('Upload New Photos') . '</a></div>'; } - $tpl = get_markup_template('photo_album.tpl'); if(count($r)) $twist = 'rotright'; foreach($r as $rr) { + if($twist == 'rotright') $twist = 'rotleft'; else @@ -1160,15 +703,36 @@ function photos_content(&$a) { $ext = $phototypes[$rr['type']]; + $imgalt_e = $rr['filename']; + $desc_e = $rr['description']; + + +// prettyphoto has potential license issues, so we can no longer include it in core +// The following lines would need to be modified so that they are provided in theme specific files +// instead of core modules for themes that wish to make use of prettyphoto. I would suggest +// the feature as a per-theme display option and putting the rel line inside a template. + +// if(feature_enabled($a->data['channel']['channel_id'],'prettyphoto')){ +// $imagelink = ($a->get_baseurl() . '/photo/' . $rr['resource_id'] . '.' . $ext ); +// $rel=("prettyPhoto[pp_gal]"); +// } +// else { + $imagelink = ($a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/image/' . $rr['resource_id'] + . (($_GET['order'] === 'posted') ? '?f=&order=posted' : '')); + $rel=("photo"); +// } + $o .= replace_macros($tpl,array( '$id' => $rr['id'], '$twist' => ' ' . $twist . rand(2,4), - '$photolink' => $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/image/' . $rr['resource_id'] - . (($_GET['order'] === 'posted') ? '?f=&order=posted' : ''), + '$photolink' => $imagelink, + '$rel' => $rel, '$phototitle' => t('View Photo'), '$imgsrc' => $a->get_baseurl() . '/photo/' . $rr['resource_id'] . '-' . $rr['scale'] . '.' .$ext, - '$imgalt' => template_escape($rr['filename']), - '$desc'=> template_escape($rr['desc']) + '$imgalt' => $imgalt_e, + '$desc'=> $desc_e, + '$ext' => $ext, + '$hash'=> $rr['resource_id'], )); } @@ -1179,33 +743,44 @@ function photos_content(&$a) { } + /** + * Display one photo + */ if($datatype === 'image') { - - - //$o = ''; // fetch image, item containing image, then comments - $ph = q("SELECT * FROM `photo` WHERE `uid` = %d AND `resource_id` = '%s' - $sql_extra ORDER BY `scale` ASC ", + $ph = q("SELECT aid,uid,xchan,resource_id,created,edited,title,`description`,album,filename,`type`,height,width,`size`,scale,profile,photo_flags,allow_cid,allow_gid,deny_cid,deny_gid FROM `photo` WHERE `uid` = %d AND `resource_id` = '%s' + and (photo_flags = %d or photo_flags = %d ) $sql_extra ORDER BY `scale` ASC ", intval($owner_uid), - dbesc($datum) + dbesc($datum), + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE) + ); - if(! count($ph)) { - $ph = q("SELECT `id` FROM `photo` WHERE `uid` = %d AND `resource_id` = '%s' + if(! $ph) { + + /* Check again - this time without specifying permissions */ + + $ph = q("SELECT id FROM photo WHERE uid = %d AND resource_id = '%s' + and ( photo_flags = %d or photo_flags = %d ) LIMIT 1", intval($owner_uid), - dbesc($datum) + dbesc($datum), + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE) ); - if(count($ph)) - notice( t('Permission denied. Access to this item may be restricted.')); + if($ph) + notice( t('Permission denied. Access to this item may be restricted.') . EOL); else notice( t('Photo not available') . EOL ); return; } + + $prevlink = ''; $nextlink = ''; @@ -1216,9 +791,11 @@ function photos_content(&$a) { $prvnxt = q("SELECT `resource_id` FROM `photo` WHERE `album` = '%s' AND `uid` = %d AND `scale` = 0 - $sql_extra ORDER BY `created` $order ", + and ( photo_flags = %d or photo_flags = %d ) $sql_extra ORDER BY `created` $order ", dbesc($ph[0]['album']), - intval($owner_uid) + intval($owner_uid), + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE) ); if(count($prvnxt)) { @@ -1233,9 +810,9 @@ function photos_content(&$a) { break; } } - $edit_suffix = ((($cmd === 'edit') && ($can_post)) ? '/edit' : ''); - $prevlink = $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/image/' . $prvnxt[$prv]['resource_id'] . $edit_suffix . (($_GET['order'] === 'posted') ? '?f=&order=posted' : ''); - $nextlink = $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/image/' . $prvnxt[$nxt]['resource_id'] . $edit_suffix . (($_GET['order'] === 'posted') ? '?f=&order=posted' : ''); + + $prevlink = $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/image/' . $prvnxt[$prv]['resource_id'] . (($_GET['order'] === 'posted') ? '?f=&order=posted' : ''); + $nextlink = $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/image/' . $prvnxt[$nxt]['resource_id'] . (($_GET['order'] === 'posted') ? '?f=&order=posted' : ''); } @@ -1258,7 +835,6 @@ function photos_content(&$a) { if($can_post && ($ph[0]['uid'] == $owner_uid)) { $tools = array( - 'edit' => array($a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/image/' . $datum . (($cmd === 'edit') ? '' : '/edit'), (($cmd === 'edit') ? t('View photo') : t('Edit photo'))), 'profile'=>array($a->get_baseurl() . '/profile_photo/use/'.$ph[0]['resource_id'], t('Use as profile photo')), ); @@ -1271,19 +847,15 @@ function photos_content(&$a) { } - if(! $cmd !== 'edit') { - $a->page['htmlhead'] .= '<script> - $(document).keydown(function(event) {' . "\n"; - - if($prevlink) - $a->page['htmlhead'] .= 'if(event.ctrlKey && event.keyCode == 37) { event.preventDefault(); window.location.href = \'' . $prevlink . '\'; }' . "\n"; - if($nextlink) - $a->page['htmlhead'] .= 'if(event.ctrlKey && event.keyCode == 39) { event.preventDefault(); window.location.href = \'' . $nextlink . '\'; }' . "\n"; - $a->page['htmlhead'] .= '});</script>'; - } + $a->page['htmlhead'] .= '<script>$(document).keydown(function(event) {' . "\n"; + if($prevlink) + $a->page['htmlhead'] .= 'if(event.ctrlKey && event.keyCode == 37) { event.preventDefault(); window.location.href = \'' . $prevlink . '\'; }' . "\n"; + if($nextlink) + $a->page['htmlhead'] .= 'if(event.ctrlKey && event.keyCode == 39) { event.preventDefault(); window.location.href = \'' . $nextlink . '\'; }' . "\n"; + $a->page['htmlhead'] .= '});</script>'; if($prevlink) - $prevlink = array($prevlink, '<div class="icon prev"></div>') ; + $prevlink = array($prevlink, '<i class="icon-backward photo-icons""></i>') ; $photo = array( 'href' => $a->get_baseurl() . '/photo/' . $hires['resource_id'] . '-' . $hires['scale'] . '.' . $phototypes[$hires['type']], @@ -1292,99 +864,98 @@ function photos_content(&$a) { ); if($nextlink) - $nextlink = array($nextlink, '<div class="icon next"></div>'); + $nextlink = array($nextlink, '<i class="icon-forward photo-icons"></i>'); // Do we have an item for this photo? - $linked_items = q("SELECT * FROM `item` WHERE `resource_id` = '%s' $sql_extra LIMIT 1", + $linked_items = q("SELECT * FROM item WHERE resource_id = '%s' and resource_type = 'photo' + $sql_extra LIMIT 1", dbesc($datum) ); - if(count($linked_items)) { + + if($linked_items) { + + xchan_query($linked_items); + $linked_items = fetch_post_tags($linked_items,true); + $link_item = $linked_items[0]; - $r = q("SELECT COUNT(*) AS `total` - FROM `item` LEFT JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - WHERE `parent_uri` = '%s' AND `uri` != '%s' AND `item`.`deleted` = 0 and `item`.`moderated` = 0 - AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0 - AND `item`.`uid` = %d - $sql_extra ", - dbesc($link_item['uri']), - dbesc($link_item['uri']), + + $r = q("select * from item where parent_mid = '%s' + and item_restrict = 0 and uid = %d $sql_extra ", + dbesc($link_item['mid']), intval($link_item['uid']) ); - if(count($r)) - $a->set_pager_total($r[0]['total']); - - - $r = q("SELECT `item`.*, `item`.`id` AS `item_id`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`network`, - `contact`.`rel`, `contact`.`thumb`, `contact`.`self`, - `contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid` - FROM `item` LEFT JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - WHERE `parent_uri` = '%s' AND `uri` != '%s' AND `item`.`deleted` = 0 and `item`.`moderated` = 0 - AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0 - AND `item`.`uid` = %d - $sql_extra - ORDER BY `parent` DESC, `id` ASC LIMIT %d ,%d ", - dbesc($link_item['uri']), - dbesc($link_item['uri']), - intval($link_item['uid']), - intval($a->pager['start']), - intval($a->pager['itemspage']) + if($r) { + xchan_query($r); + $r = fetch_post_tags($r,true); + $r = conv_sort($r,'commented'); + } + + + + $tags = array(); + if($link_item['term']) { + $cnt = 0; + foreach($link_item['term'] as $t) + $tags[$cnt] = array(0 => format_term_for_display($t)); + if($can_post && ($ph[0]['uid'] == $owner_uid)) { + $tags[$cnt][1] = 'tagrm?f=&item=' . $link_item['id']; + $tags[$cnt][2] = t('Remove'); + } + $cnt ++; + } + - ); - if((local_user()) && (local_user() == $link_item['uid'])) { - q("UPDATE `item` SET `unseen` = 0 WHERE `parent` = %d and `uid` = %d", + q("UPDATE `item` SET item_flags = (item_flags ^ %d) WHERE parent = %d and uid = %d and (item_flags & %d)", + intval(ITEM_UNSEEN), intval($link_item['parent']), - intval(local_user()) + intval(local_user()), + intval(ITEM_UNSEEN) ); } } - $tags=Null; - - if(count($linked_items) && strlen($link_item['tag'])) { - $arr = explode(',',$link_item['tag']); - // parse tags and add links - $tag_str = ''; - foreach($arr as $t) { - if(strlen($tag_str)) - $tag_str .= ', '; - $tag_str .= bbcode($t); - } - $tags = array(t('Tags: '), $tag_str); - if($cmd === 'edit') { - $tags[] = $a->get_baseurl() . '/tagrm/' . $link_item['id']; - $tags[] = t('[Remove any tag]'); - } - } +// logger('mod_photo: link_item' . print_r($link_item,true)); + + // FIXME - remove this when we move to conversation module + $r = $r[0]['children']; - $edit = Null; - if(($cmd === 'edit') && ($can_post)) { - $edit_tpl = get_markup_template('photo_edit.tpl'); - $edit = replace_macros($edit_tpl, array( - '$id' => $ph[0]['id'], - '$rotatecw' => t('Rotate CW (right)'), - '$rotateccw' => t('Rotate CCW (left)'), - '$album' => template_escape($ph[0]['album']), - '$newalbum' => t('New album name'), - '$nickname' => $a->data['channel']['channel_address'], - '$resource_id' => $ph[0]['resource_id'], - '$capt_label' => t('Caption'), - '$caption' => template_escape($ph[0]['desc']), - '$tag_label' => t('Add a Tag'), - '$tags' => $link_item['tag'], - '$permissions' => t('Permissions'), - '$aclselect' => template_escape(populate_acl($ph[0])), - '$help_tags' => t('Example: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping'), - '$item_id' => ((count($linked_items)) ? $link_item['id'] : 0), - '$submit' => t('Submit'), - '$delete' => t('Delete Photo') - )); + $edit = null; + if($can_post) { + if(array_key_exists('albums', $a->data)) + $albums = get_app()->data['albums']; + else + $albums = photos_albums_list($a->data['channel'],$a->data['observer']); + + $album_e = $ph[0]['album']; + $caption_e = $ph[0]['description']; + $aclselect_e = populate_acl($ph[0]); + + $edit = array( + 'edit' => t('Edit photo'), + 'id' => $ph[0]['id'], + 'rotatecw' => t('Rotate CW (right)'), + 'rotateccw' => t('Rotate CCW (left)'), + 'albums' => $albums['albums'], + 'album' => $album_e, + 'newalbum' => t('New album name'), + 'nickname' => $a->data['channel']['channel_address'], + 'resource_id' => $ph[0]['resource_id'], + 'capt_label' => t('Caption'), + 'caption' => $caption_e, + 'tag_label' => t('Add a Tag'), + 'permissions' => t('Permissions'), + 'aclselect' => $aclselect_e, + 'help_tags' => t('Example: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping'), + 'item_id' => ((count($linked_items)) ? $link_item['id'] : 0), + 'submit' => t('Submit'), + 'delete' => t('Delete Photo') + ); } if(count($linked_items)) { @@ -1397,7 +968,7 @@ function photos_content(&$a) { $likebuttons = ''; - if($can_post || $a->data['perms']['post_comments']) { + if($can_post || $can_comment) { $likebuttons = replace_macros($like_tpl,array( '$id' => $link_item['id'], '$likethis' => t("I like this \x28toggle\x29"), @@ -1409,21 +980,23 @@ function photos_content(&$a) { $comments = ''; if(! count($r)) { - if($can_post || $a->data['perms']['post_comments']) { + if($can_post || $can_comment) { $comments .= replace_macros($cmnt_tpl,array( '$return_path' => '', + '$mode' => 'photos', '$jsreload' => $return_url, '$type' => 'wall-comment', '$id' => $link_item['id'], '$parent' => $link_item['id'], '$profile_uid' => $owner_uid, - '$mylink' => $contact['url'], + '$mylink' => $observer['xchan_url'], '$mytitle' => t('This is you'), - '$myphoto' => $contact['thumb'], + '$myphoto' => $observer['xchan_photo_s'], '$comment' => t('Comment'), '$submit' => t('Submit'), '$preview' => t('Preview'), - '$ww' => '' + '$ww' => '', + '$feature_encrypt' => false )); } } @@ -1435,7 +1008,7 @@ function photos_content(&$a) { $dislike = ''; // display comments - if(count($r)) { + if($r) { foreach($r as $item) { like_puller($a,$item,$alike,'like'); @@ -1447,23 +1020,6 @@ function photos_content(&$a) { - if($can_post || $a->data['perms']['post_comments']) { - $comments .= replace_macros($cmnt_tpl,array( - '$return_path' => '', - '$jsreload' => $return_url, - '$type' => 'wall-comment', - '$id' => $link_item['id'], - '$parent' => $link_item['id'], - '$profile_uid' => $owner_uid, - '$mylink' => $contact['url'], - '$mytitle' => t('This is you'), - '$myphoto' => $contact['thumb'], - '$comment' => t('Comment'), - '$submit' => t('Submit'), - '$ww' => '' - )); - } - foreach($r as $item) { $comment = ''; $template = $tpl; @@ -1474,85 +1030,91 @@ function photos_content(&$a) { $redirect_url = $a->get_baseurl() . '/redir/' . $item['cid'] ; - if($can_post || $a->data['perms']['post_comments']) { - $comments .= replace_macros($cmnt_tpl,array( - '$return_path' => '', - '$jsreload' => $return_url, - '$type' => 'wall-comment', - '$id' => $item['item_id'], - '$parent' => $item['parent'], - '$profile_uid' => $owner_uid, - '$mylink' => $contact['url'], - '$mytitle' => t('This is you'), - '$myphoto' => $contact['thumb'], - '$comment' => t('Comment'), - '$submit' => t('Submit'), - '$sourceapp' => t($a->sourcename), - '$ww' => '' - )); - } + $profile_url = zid($item['author']['xchan_url']); + $sparkle = ''; - if(local_user() && ($item['contact-uid'] == local_user()) - && ($item['network'] == 'dfrn') && (! $item['self'] )) { - $profile_url = $redirect_url; - $sparkle = ' sparkle'; - } - else { - $profile_url = $item['url']; - $sparkle = ''; - } - - $diff_author = (($item['url'] !== $item['author-link']) ? true : false); - $profile_name = (((strlen($item['author-name'])) && $diff_author) ? $item['author-name'] : $item['name']); - $profile_avatar = (((strlen($item['author-avatar'])) && $diff_author) ? $item['author-avatar'] : $item['thumb']); + $profile_name = $item['author']['xchan_name']; + $profile_avatar = $item['author']['xchan_photo_m']; $profile_link = $profile_url; $drop = ''; - if(($item['contact-id'] == $contact_id) || ($item['uid'] == local_user())) + if($observer['xchan_hash'] === $item['author_xchan'] || $observer['xchan_hash'] === $item['owner_xchan']) $drop = replace_macros(get_markup_template('photo_drop.tpl'), array('$id' => $item['id'], '$delete' => t('Delete'))); + $name_e = $profile_name; + $title_e = $item['title']; + unobscure($item); + $body_e = prepare_text($item['body'],$item['mimetype']); + $comments .= replace_macros($template,array( '$id' => $item['item_id'], + '$mode' => 'photos', '$profile_url' => $profile_link, - '$name' => template_escape($profile_name), + '$name' => $name_e, '$thumb' => $profile_avatar, '$sparkle' => $sparkle, - '$title' => template_escape($item['title']), - '$body' => template_escape(bbcode($item['body'])), + '$title' => $title_e, + '$body' => $body_e, '$ago' => relative_date($item['created']), '$indent' => (($item['parent'] != $item['item_id']) ? ' comment' : ''), '$drop' => $drop, '$comment' => $comment )); + + } + + if($can_post || $can_comment) { + $comments .= replace_macros($cmnt_tpl,array( + '$return_path' => '', + '$jsreload' => $return_url, + '$type' => 'wall-comment', + '$id' => $link_item['id'], + '$parent' => $link_item['id'], + '$profile_uid' => $owner_uid, + '$mylink' => $observer['xchan_url'], + '$mytitle' => t('This is you'), + '$myphoto' => $observer['xchan_photo_s'], + '$comment' => t('Comment'), + '$submit' => t('Submit'), + '$ww' => '' + )); } - } + } $paginate = paginate($a); } + $album_e = array($album_link,$ph[0]['album']); + $like_e = $like; + $dislike_e = $dislike; + + $photo_tpl = get_markup_template('photo_view.tpl'); $o .= replace_macros($photo_tpl, array( '$id' => $ph[0]['id'], - '$album' => array($album_link,template_escape($ph[0]['album'])), + '$album' => $album_e, '$tools' => $tools, '$lock' => $lock, '$photo' => $photo, '$prevlink' => $prevlink, '$nextlink' => $nextlink, - '$desc' => $ph[0]['desc'], - '$tags' => template_escape($tags), + '$desc' => $ph[0]['description'], + '$tag_hdr' => t('In This Photo:'), + '$tags' => $tags, '$edit' => $edit, '$likebuttons' => $likebuttons, - '$like' => template_escape($like), - '$dislike' => template_escape($dislike), + '$like' => $like_e, + '$dislike' => $dislike_e, '$comments' => $comments, '$paginate' => $paginate, )); + + $a->data['photo_html'] = $o; return $o; } @@ -1561,10 +1123,12 @@ function photos_content(&$a) { //$o = ''; $r = q("SELECT `resource_id`, max(`scale`) AS `scale` FROM `photo` WHERE `uid` = %d AND `album` != '%s' AND `album` != '%s' - $sql_extra GROUP BY `resource_id`", + and ( photo_flags = %d or photo_flags = %d ) $sql_extra GROUP BY `resource_id`", intval($a->data['channel']['channel_id']), dbesc('Contact Photos'), - dbesc( t('Contact Photos')) + dbesc( t('Contact Photos')), + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE) ); if(count($r)) { $a->set_pager_total(count($r)); @@ -1572,11 +1136,14 @@ function photos_content(&$a) { } $r = q("SELECT `resource_id`, `id`, `filename`, type, `album`, max(`scale`) AS `scale` FROM `photo` - WHERE `uid` = %d AND `album` != '%s' AND `album` != '%s' + WHERE `uid` = %d AND `album` != '%s' AND `album` != '%s' + and ( photo_flags = %d or photo_flags = %d ) $sql_extra GROUP BY `resource_id` ORDER BY `created` DESC LIMIT %d , %d", intval($a->data['channel']['channel_id']), dbesc('Contact Photos'), dbesc( t('Contact Photos')), + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), intval($a->pager['start']), intval($a->pager['itemspage']) ); @@ -1593,16 +1160,25 @@ function photos_content(&$a) { $twist = 'rotright'; $ext = $phototypes[$rr['type']]; + if($a->get_template_engine() === 'internal') { + $alt_e = template_escape($rr['filename']); + $name_e = template_escape($rr['album']); + } + else { + $alt_e = $rr['filename']; + $name_e = $rr['album']; + } + $photos[] = array( 'id' => $rr['id'], 'twist' => ' ' . $twist . rand(2,4), 'link' => $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/image/' . $rr['resource_id'], 'title' => t('View Photo'), 'src' => $a->get_baseurl() . '/photo/' . $rr['resource_id'] . '-' . ((($rr['scale']) == 6) ? 4 : $rr['scale']) . '.' . $ext, - 'alt' => template_escape($rr['filename']), + 'alt' => $alt_e, 'album' => array( 'link' => $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/album/' . bin2hex($rr['album']), - 'name' => template_escape($rr['album']), + 'name' => $name_e, 'alt' => t('View Album'), ), @@ -1611,7 +1187,7 @@ function photos_content(&$a) { } $tpl = get_markup_template('photos_recent.tpl'); - $o .= replace_macros($tpl,array( + $o .= replace_macros($tpl, array( '$title' => t('Recent Photos'), '$can_post' => $can_post, '$upload' => array(t('Upload New Photos'), $a->get_baseurl().'/photos/'.$a->data['channel']['channel_address'].'/upload'), diff --git a/mod/ping.php b/mod/ping.php index 76d139711..ac12e2fc0 100644 --- a/mod/ping.php +++ b/mod/ping.php @@ -43,11 +43,87 @@ function ping_init(&$a) { unset($_SESSION['sysmsg_info']); } + if($a->install) { + echo json_encode($result); + killme(); + } + + + if(get_observer_hash() && (! $result['invalid'])) { + $r = q("select cp_id, cp_room from chatpresence where cp_xchan = '%s' and cp_client = '%s' and cp_room = 0 limit 1", + dbesc(get_observer_hash()), + dbesc($_SERVER['REMOTE_ADDR']) + ); + $basic_presence = false; + if($r) { + $basic_presence = true; + q("update chatpresence set cp_last = '%s' where cp_id = %d limit 1", + dbesc(datetime_convert()), + intval($r[0]['cp_id']) + ); + } + if(! $basic_presence) { + q("insert into chatpresence ( cp_xchan, cp_last, cp_status, cp_client) + values( '%s', '%s', '%s', '%s' ) ", + dbesc(get_observer_hash()), + dbesc(datetime_convert()), + dbesc('online'), + dbesc($_SERVER['REMOTE_ADDR']) + ); + } + } + + q("delete from chatpresence where cp_last < UTC_TIMESTAMP() - INTERVAL 3 MINUTE and cp_client != 'auto' "); + if((! local_user()) || ($result['invalid'])) { echo json_encode($result); killme(); } + if(x($_REQUEST,'markRead') && local_user()) { + + switch($_REQUEST['markRead']) { + case 'network': + $r = q("update item set item_flags = ( item_flags ^ %d ) where (item_flags & %d) and uid = %d", + intval(ITEM_UNSEEN), + intval(ITEM_UNSEEN), + intval(local_user()) + ); + break; + + case 'home': + $r = q("update item set item_flags = ( item_flags ^ %d ) where (item_flags & %d) and (item_flags & %d) and uid = %d", + intval(ITEM_UNSEEN), + intval(ITEM_UNSEEN), + intval(ITEM_WALL), + intval(local_user()) + ); + break; + case 'messages': + $r = q("update mail set mail_flags = ( mail_flags ^ %d ) where channel_id = %d and not (mail_flags & %d)", + intval(MAIL_SEEN), + intval(local_user()), + intval(MAIL_SEEN) + ); + break; + case 'all_events': + $r = q("update event set `ignore` = 1 where `ignore` = 0 and uid = %d", + intval(local_user()) + ); + break; + + case 'notify': + $r = q("update notify set seen = 1 where uid = %d", + intval(local_user()) + ); + break; + + default: + break; + } + } + + if(argc() > 1 && argv(1) === 'notify') { $t = q("select count(*) as total from notify where uid = %d and seen = 0", intval(local_user()) @@ -75,7 +151,7 @@ function ping_init(&$a) { foreach($z as $zz) { $notifs[] = array( 'notify_link' => $a->get_baseurl() . '/notify/view/' . $zz['id'], - 'name' => $zz['name'], + 'name' => '', // not required here because the name is in the message 'url' => $zz['url'], 'photo' => $zz['photo'], 'when' => relative_date($zz['date']), @@ -90,6 +166,42 @@ function ping_init(&$a) { } + + if(argc() > 1 && argv(1) === 'messages') { + + $channel = $a->get_channel(); + $t = q("select mail.*, xchan.* from mail left join xchan on xchan_hash = from_xchan + where channel_id = %d and not ( mail_flags & %d ) and not (mail_flags & %d ) + and from_xchan != '%s' order by created desc limit 0,50", + intval(local_user()), + intval(MAIL_SEEN), + intval(MAIL_DELETED), + dbesc($channel['channel_hash']) + ); + + if($t) { + foreach($t as $zz) { +// $msg = sprintf( t('sent you a private message.'), $zz['xchan_name']); + $notifs[] = array( + 'notify_link' => $a->get_baseurl() . '/mail/' . $zz['id'], + 'name' => $zz['xchan_name'], + 'url' => $zz['xchan_url'], + 'photo' => $zz['xchan_photo_s'], + 'when' => relative_date($zz['created']), + 'class' => (($zz['mail_flags'] & MAIL_SEEN) ? 'notify-seen' : 'notify-unseen'), + 'message' => t('sent you a private message'), + ); + } + } + + echo json_encode(array('notify' => $notifs)); + killme(); + + } + + + + if(argc() > 1 && (argv(1) === 'network' || argv(1) === 'home')) { $result = array(); @@ -110,12 +222,12 @@ function ping_init(&$a) { } } logger('ping: ' . print_r($result,true)); - echo json_encode(array( argv(1) => $result)); + echo json_encode(array('notify' => $result)); killme(); } - if(argc() > 1 && (argv(1) === 'connect')) { + if(argc() > 1 && (argv(1) === 'intros')) { $result = array(); @@ -129,18 +241,62 @@ function ping_init(&$a) { if($r) { foreach($r as $rr) { $result[] = array( - 'notify_link' => $a->get_baseurl() . '/notify/view-intro/' . $rr['abook_id'], + 'notify_link' => $a->get_baseurl() . '/connedit/' . $rr['abook_id'], 'name' => $rr['xchan_name'], 'url' => $rr['xchan_url'], 'photo' => $rr['xchan_photo_s'], 'when' => relative_date($rr['abook_created']), 'class' => ('notify-unseen'), - 'message' => strip_tags(sprintf( t("Connection request from %s"), $rr['xchan_name'])) + 'message' => t('added your channel') ); } } logger('ping: ' . print_r($result,true)); - echo json_encode(array( argv(1) => $result)); + echo json_encode(array('notify' => $result)); + killme(); + + } + + if(argc() > 1 && (argv(1) === 'all_events')) { + + $bd_format = t('g A l F d') ; // 8 AM Friday January 18 + + $result = array(); + + $r = q("SELECT * FROM event left join xchan on event_xchan = xchan_hash + WHERE `event`.`uid` = %d AND start < '%s' AND start > '%s' and `ignore` = 0 + ORDER BY `start` DESC ", + intval(local_user()), + dbesc(datetime_convert('UTC',date_default_timezone_get(),'now + 7 days')), + dbesc(datetime_convert('UTC',date_default_timezone_get(),'now - 1 days')) + ); + + if($r) { + foreach($r as $rr) { + if($rr['adjust']) + $md = datetime_convert('UTC',date_default_timezone_get(),$rr['start'],'Y/m'); + else + $md = datetime_convert('UTC','UTC',$rr['start'],'Y/m'); + + $strt = datetime_convert('UTC',$rr['convert'] ? date_default_timezone_get() : 'UTC',$rr['start']); + $today = ((substr($strt,0,10) === datetime_convert('UTC',date_default_timezone_get(),'now','Y-m-d')) ? true : false); + + $when = day_translate(datetime_convert('UTC', $rr['adjust'] ? date_default_timezone_get() : 'UTC', $rr['start'], $bd_format)) . (($today) ? ' ' . t('[today]') : ''); + + + $result[] = array( + 'notify_link' => $a->get_baseurl() . '/events', // FIXME this takes you to an edit page and it may not be yours, we really want to just view the single event --> '/events/event/' . $rr['event_hash'], + 'name' => $rr['xchan_name'], + 'url' => $rr['xchan_url'], + 'photo' => $rr['xchan_photo_s'], + 'when' => $when, + 'class' => ('notify-unseen'), + 'message' => t('posted an event') + ); + } + } + logger('ping: ' . print_r($result,true)); + echo json_encode(array('notify' => $result)); killme(); } @@ -202,8 +358,10 @@ function ping_init(&$a) { if($mails) $result['mail'] = intval($mails[0]['total']); - if ($a->config['system']['register_policy'] == REGISTER_APPROVE && is_site_admin()){ - $regs = q("SELECT `contact`.`name`, `contact`.`url`, `contact`.`micro`, `register`.`created`, COUNT(*) as `total` FROM `contact` RIGHT JOIN `register` ON `register`.`uid`=`contact`.`uid` WHERE `contact`.`self`=1"); + if ($a->config['system']['register_policy'] == REGISTER_APPROVE && is_site_admin()) { + $regs = q("SELECT count(account_id) as total from account where (account_flags & %d)", + intval(ACCOUNT_PENDING) + ); if($regs) $result['register'] = intval($regs[0]['total']); } @@ -211,11 +369,11 @@ function ping_init(&$a) { $t5 = dba_timer(); $events = q("SELECT type, start, adjust FROM `event` - WHERE `event`.`uid` = %d AND `start` < '%s' AND `finish` > '%s' and `ignore` = 0 + WHERE `event`.`uid` = %d AND start < '%s' AND start > '%s' and `ignore` = 0 ORDER BY `start` ASC ", intval(local_user()), - dbesc(datetime_convert('UTC','UTC','now + 7 days')), - dbesc(datetime_convert('UTC','UTC','now')) + dbesc(datetime_convert('UTC',date_default_timezone_get(),'now + 7 days')), + dbesc(datetime_convert('UTC',date_default_timezone_get(),'now - 1 days')) ); if($events) { diff --git a/mod/poco.php b/mod/poco.php index c0dc2e133..9295f13de 100644 --- a/mod/poco.php +++ b/mod/poco.php @@ -4,9 +4,10 @@ function poco_init(&$a) { $system_mode = false; - if(intval(get_config('system','block_public'))) + if(intval(get_config('system','block_public')) && (! local_user()) && (! remote_user())) { + logger('mod_poco: block_public'); http_status_exit(401); - + } $observer = $a->get_observer(); @@ -15,8 +16,10 @@ function poco_init(&$a) { } if(! x($user)) { $c = q("select * from pconfig where cat = 'system' and k = 'suggestme' and v = 1"); - if(! count($c)) - http_status_exit(401); + if(! $c) { + logger('mod_poco: system mode. No candidates.', LOGGER_DEBUG); + http_status_exit(404); + } $system_mode = true; } @@ -36,19 +39,23 @@ function poco_init(&$a) { if(argc() > 4 && intval(argv(4)) && $justme == false) $cid = intval(argv(4)); - if(! $system_mode) { - $r = q("SELECT channel.channel_id from channel where channel_address = '%s' limit 1", + $r = q("SELECT channel_id from channel where channel_address = '%s' limit 1", dbesc($user) ); - if(! $r) + if(! $r) { + logger('mod_poco: user mode. Account not found. ' . $user); http_status_exit(404); + } $channel_id = $r[0]['channel_id']; + $ohash = (($observer) ? $observer['xchan_hash'] : ''); - if(! perm_is_allowed($channel_id,$observer,'view_contacts')) - http_status_exit(404); + if(! perm_is_allowed($channel_id,$ohash,'view_contacts')) { + logger('mod_poco: user mode. Permission denied for ' . $ohash . ' user: ' . $user); + http_status_exit(401); + } } @@ -69,6 +76,9 @@ function poco_init(&$a) { $sql_extra ", intval($channel_id) ); + $c = q("select * from menu_item where ( mitem_flags & " . intval(MENU_ITEM_CHATROOM) . " ) and allow_cid = '' and allow_gid = '' and deny_cid = '' and deny_gid = '' and mitem_channel_id = %d", + intval($channel_id) + ); } if($r) $totalResults = intval($r[0]['total']); @@ -108,6 +118,14 @@ function poco_init(&$a) { $ret['startIndex'] = (string) $startIndex; $ret['itemsPerPage'] = (string) $itemsPerPage; $ret['totalResults'] = (string) $totalResults; + + if($c) { + $ret['chatrooms'] = array(); + foreach($c as $d) { + $ret['chatrooms'][] = array('url' => $d['mitem_link'], 'desc' => $d['mitem_desc']); + } + } + $ret['entry'] = array(); @@ -119,10 +137,8 @@ function poco_init(&$a) { 'displayName' => false, 'urls' => false, 'preferredUsername' => false, - 'photos' => false - - - + 'photos' => false, + 'rating' => false ); if((! x($_GET,'fields')) || ($_GET['fields'] === '@all')) @@ -158,6 +174,12 @@ function poco_init(&$a) { $entry['preferredUsername'] = substr($rr['xchan_addr'],0,strpos($rr['xchan_addr'],'@')); if($fields_ret['photos']) $entry['photos'] = array(array('value' => $rr['xchan_photo_l'], 'mimetype' => $rr['xchan_photo_mimetype'], 'type' => 'profile')); + if($fields_ret['rating']) { + $entry['rating'] = ((array_key_exists('abook_rating',$rr)) ? array(intval($rr['abook_rating'])) : 0); + // maybe this should be a composite calculated rating in $system_mode + if($system_mode) + $entry['rating'] = 0; + } $ret['entry'][] = $entry; } } diff --git a/mod/poke.php b/mod/poke.php index 163ef0cd8..b22f7d9d5 100755 --- a/mod/poke.php +++ b/mod/poke.php @@ -1,17 +1,30 @@ -<?php +<?php /** @file */ + +/** + * + * Poke, prod, finger, or otherwise do unspeakable things to somebody - who must be a connection in your address book + * This function can be invoked with the required arguments (verb and cid and private and possibly parent) silently via ajax or + * other web request. You must be logged in and connected to a channel. + * If the required arguments aren't present, we'll display a simple form to choose a recipient and a verb. + * parent is a special argument which let's you attach this activity as a comment to an existing conversation, which + * may have started with somebody else poking (etc.) somebody, but this isn't necessary. This can be used in the adult + * plugin version to have entire conversations where Alice poked Bob, Bob fingered Alice, Alice hugged Bob, etc. + * + * private creates a private conversation with the recipient. Otherwise your channel's default post privacy is used. + * + */ -require_once('include/security.php'); -require_once('include/bbcode.php'); require_once('include/items.php'); - function poke_init(&$a) { if(! local_user()) return; $uid = local_user(); - $verb = notags(trim($_GET['verb'])); + $channel = $a->get_channel(); + + $verb = notags(trim($_REQUEST['verb'])); if(! $verb) return; @@ -23,109 +36,86 @@ function poke_init(&$a) { $activity = ACTIVITY_POKE . '#' . urlencode($verbs[$verb][0]); - $contact_id = intval($_GET['cid']); + $contact_id = intval($_REQUEST['cid']); if(! $contact_id) return; - $parent = ((x($_GET,'parent')) ? intval($_GET['parent']) : 0); - + $parent = ((x($_REQUEST,'parent')) ? intval($_REQUEST['parent']) : 0); logger('poke: verb ' . $verb . ' contact ' . $contact_id, LOGGER_DEBUG); - $r = q("SELECT * FROM `contact` WHERE `id` = %d and `uid` = %d LIMIT 1", + $r = q("SELECT * FROM abook left join xchan on xchan_hash = abook_xchan where abook_id = %d and abook_channel = %d LIMIT 1", intval($contact_id), intval($uid) ); - if(! count($r)) { - logger('poke: no contact ' . $contact_id); + if(! $r) { + logger('poke: no target ' . $contact_id); return; } $target = $r[0]; + $parent_item = null; if($parent) { - $r = q("select uri, private, allow_cid, allow_gid, deny_cid, deny_gid + $r = q("select mid, item_private, owner_xchan, allow_cid, allow_gid, deny_cid, deny_gid from item where id = %d and parent = %d and uid = %d limit 1", intval($parent), intval($parent), intval($uid) ); - if(count($r)) { - $parent_uri = $r[0]['uri']; - $private = $r[0]['private']; - $allow_cid = $r[0]['allow_cid']; - $allow_gid = $r[0]['allow_gid']; - $deny_cid = $r[0]['deny_cid']; - $deny_gid = $r[0]['deny_gid']; + if($r) { + $parent_item = $r[0]; + $parent_mid = $r[0]['mid']; + $item_private = $r[0]['item_private']; + $allow_cid = $r[0]['allow_cid']; + $allow_gid = $r[0]['allow_gid']; + $deny_cid = $r[0]['deny_cid']; + $deny_gid = $r[0]['deny_gid']; } } else { - $private = ((x($_GET,'private')) ? intval($_GET['private']) : 0); + $item_private = ((x($_GET,'private')) ? intval($_GET['private']) : 0); - $allow_cid = (($private) ? '<' . $target['id']. '>' : $a->user['allow_cid']); - $allow_gid = (($private) ? '' : $a->user['allow_gid']); - $deny_cid = (($private) ? '' : $a->user['deny_cid']); - $deny_gid = (($private) ? '' : $a->user['deny_gid']); + $allow_cid = (($item_private) ? '<' . $target['abook_xchan']. '>' : $channel['channel_allow_cid']); + $allow_gid = (($item_private) ? '' : $channel['channel_allow_gid']); + $deny_cid = (($item_private) ? '' : $channel['channel_deny_cid']); + $deny_gid = (($item_private) ? '' : $channel['channel_deny_gid']); } - - - $poster = $a->contact; - - $uri = item_message_id(); - $arr = array(); + $arr['item_flags'] = ITEM_WALL | ITEM_ORIGIN; + if($parent_item) + $arr['item_flags'] |= ITEM_THREAD_TOP; - $arr['uid'] = $uid; - $arr['uri'] = $uri; - $arr['parent_uri'] = (($parent_uri) ? $parent_uri : $uri); - $arr['type'] = 'activity'; - $arr['wall'] = 1; - $arr['contact-id'] = $poster['id']; - $arr['owner-name'] = $poster['name']; - $arr['owner-link'] = $poster['url']; - $arr['owner-avatar'] = $poster['thumb']; - $arr['author-name'] = $poster['name']; - $arr['author-link'] = $poster['url']; - $arr['author-avatar'] = $poster['thumb']; + $arr['owner_xchan'] = (($parent_item) ? $parent_item['owner_xchan'] : $channel['channel_hash']); + $arr['parent_mid'] = (($parent_mid) ? $parent_mid : $mid); $arr['title'] = ''; $arr['allow_cid'] = $allow_cid; $arr['allow_gid'] = $allow_gid; $arr['deny_cid'] = $deny_cid; $arr['deny_gid'] = $deny_gid; - $arr['last-child'] = 1; - $arr['visible'] = 1; $arr['verb'] = $activity; - $arr['private'] = $private; - $arr['obj_type'] = ACTIVITY_OBJ_PERSON; - - $arr['origin'] = 1; - $arr['body'] = '[url=' . $poster['url'] . ']' . $poster['name'] . '[/url]' . ' ' . t($verbs[$verb][0]) . ' ' . '[url=' . $target['url'] . ']' . $target['name'] . '[/url]'; - - $arr['object'] = '<object><type>' . ACTIVITY_OBJ_PERSON . '</type><title>' . $target['name'] . '</title><id>' . $a->get_baseurl() . '/contact/' . $target['id'] . '</id>'; - $arr['object'] .= '<link>' . xmlify('<link rel="alternate" type="text/html" href="' . $target['url'] . '" />' . "\n"); - - $arr['object'] .= xmlify('<link rel="photo" type="image/jpeg" href="' . $target['photo'] . '" />' . "\n"); - $arr['object'] .= '</link></object>' . "\n"; - - $item_id = item_store($arr); - if($item_id) { - q("UPDATE `item` SET `plink` = '%s' WHERE `uid` = %d AND `id` = %d LIMIT 1", - dbesc($a->get_baseurl() . '/display/' . $poster['nickname'] . '/' . $item_id), - intval($uid), - intval($item_id) - ); - proc_run('php',"include/notifier.php","tag","$item_id"); - } - + $arr['item_private'] = $item_private; + $arr['obj_type'] = ACTIVITY_OBJ_PERSON; + $arr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t($verbs[$verb][0]) . ' ' . '[zrl=' . $target['xchan_url'] . ']' . $target['xchan_name'] . '[/zrl]'; + + $obj = array( + 'type' => ACTIVITY_OBJ_PERSON, + 'title' => $target['xchan_name'], + 'id' => $target['xchan_hash'], + 'link' => array( + array('rel' => 'alternate', 'type' => 'text/html', 'href' => $target['xchan_url']), + array('rel' => 'photo', 'type' => $target['xchan_photo_mimetype'], 'href' => $target['xchan_photo_l']) + ), + ); - call_hooks('post_local_end', $arr); + $arr['object'] = json_encode($obj); - proc_run('php',"include/notifier.php","like","$post_id"); + post_activity_item($arr); return; } @@ -142,43 +132,19 @@ function poke_content(&$a) { $name = ''; $id = ''; - if(intval($_GET['c'])) { - $r = q("select id,name from contact where id = %d and uid = %d limit 1", - intval($_GET['c']), + if(intval($_REQUEST['c'])) { + $r = q("select abook_id, xchan_name from abook left join xchan on abook_xchan = xchan_hash + where abook_id = %d and abook_channel = %d limit 1", + intval($_REQUEST['c']), intval(local_user()) ); - if(count($r)) { - $name = $r[0]['name']; - $id = $r[0]['id']; + if($r) { + $name = $r[0]['xchan_name']; + $id = $r[0]['abook_id']; } } - - $base = $a->get_baseurl(); - - $a->page['htmlhead'] .= <<< EOT - -<script>$(document).ready(function() { - var a; - a = $("#poke-recip").autocomplete({ - serviceUrl: '$base/acl', - minChars: 2, - width: 350, - onSelect: function(value,data) { - $("#poke-recip-complete").val(data); - } - }); - a.setOptions({ params: { type: 'a' }}); - - -}); - -</script> -EOT; - - $parent = ((x($_GET,'parent')) ? intval($_GET['parent']) : '0'); - - + $parent = ((x($_REQUEST,'parent')) ? intval($_REQUEST['parent']) : '0'); $verbs = get_poke_verbs(); diff --git a/mod/post.php b/mod/post.php index 53180e1c1..05053e798 100644 --- a/mod/post.php +++ b/mod/post.php @@ -1,4 +1,4 @@ -<?php +<?php /** @file */ /** * Zot endpoint @@ -6,36 +6,519 @@ require_once('include/zot.php'); + + +function post_init(&$a) { + + // Most access to this endpoint is via the post method. + // Here we will pick out the magic auth params which arrive + // as a get request, and the only communications to arrive this way. + +/** + * Magic Auth + * ========== + * + * So-called "magic auth" takes place by a special exchange. On the site where the "channel to be authenticated" lives (e.g. $mysite), + * a redirection is made via $mysite/magic to the zot endpoint of the remote site ($remotesite) with special GET parameters. + * + * The endpoint is typically https://$remotesite/post - or whatever was specified as the callback url in prior communications + * (we will bootstrap an address and fetch a zot info packet if possible where no prior communications exist) + * + * Four GET parameters are supplied: + * + ** auth => the urlencoded webbie (channel@host.domain) of the channel requesting access + ** dest => the desired destination URL (urlencoded) + ** sec => a random string which is also stored on $mysite for use during the verification phase. + ** version => the zot revision + * + * When this packet is received, an "auth-check" zot message is sent to $mysite. + * (e.g. if $_GET['auth'] is foobar@podunk.edu, a zot packet is sent to the podunk.edu zot endpoint, which is typically /post) + * If no information has been recorded about the requesting identity a zot information packet will be retrieved before + * continuing. + * + * The sender of this packet is an arbitrary/random site channel. The recipients will be a single recipient corresponding + * to the guid and guid_sig we have associated with the requesting auth identity + * + * + * { + * "type":"auth_check", + * "sender":{ + * "guid":"kgVFf_...", + * "guid_sig":"PT9-TApz...", + * "url":"http:\/\/podunk.edu", + * "url_sig":"T8Bp7j..." + * }, + * "recipients":{ + * { + * "guid":"ZHSqb...", + * "guid_sig":"JsAAXi..." + * } + * } + * "callback":"\/post", + * "version":1, + * "secret":"1eaa661", + * "secret_sig":"eKV968b1..." + * } + * + * + * auth_check messages MUST use encapsulated encryption. This message is sent to the origination site, which checks the 'secret' to see + * if it is the same as the 'sec' which it passed originally. It also checks the secret_sig which is the secret signed by the + * destination channel's private key and base64url encoded. If everything checks out, a json packet is returned: + * + * { + * "success":1, + * "confirm":"q0Ysovd1u..." + * "service_class":(optional) + * "level":(optional) + * } + * + * 'confirm' in this case is the base64url encoded RSA signature of the concatenation of 'secret' with the + * base64url encoded whirlpool hash of the requestor's guid and guid_sig; signed with the source channel private key. + * This prevents a man-in-the-middle from inserting a rogue success packet. Upon receipt and successful + * verification of this packet, the destination site will redirect to the original destination URL and indicate a successful remote login. + * Service_class can be used by cooperating sites to provide different access rights based on account rights and subscription plans. It is + * a string whose contents are not defined by protocol. Example: "basic" or "gold". + * + * + * + */ + + if(array_key_exists('auth',$_REQUEST)) { + + $ret = array('success' => false, 'message' => ''); + + logger('mod_zot: auth request received.'); + $address = $_REQUEST['auth']; + $desturl = $_REQUEST['dest']; + $sec = $_REQUEST['sec']; + $version = $_REQUEST['version']; + $test = ((x($_REQUEST,'test')) ? intval($_REQUEST['test']) : 0); + + // They are authenticating ultimately to the site and not to a particular channel. + // Any channel will do, providing it's currently active. We just need to have an + // identity to attach to the packet we send back. So find one. + + $c = q("select * from channel where not ( channel_pageflags & %d ) limit 1", + intval(PAGE_REMOVED) + ); + + if(! $c) { + // nobody here + logger('mod_zot: auth: unable to find a response channel'); + if($test) { + $ret['message'] .= 'no local channels found.' . EOL; + json_return_and_die($ret); + } + + goaway($desturl); + } + + // Try and find a hubloc for the person attempting to auth + $x = q("select * from hubloc left join xchan on xchan_hash = hubloc_hash where hubloc_addr = '%s' order by hubloc_id desc limit 1", + dbesc($address) + ); + + if(! $x) { + // finger them if they can't be found. + $ret = zot_finger($address,null); + if($ret['success']) { + $j = json_decode($ret['body'],true); + if($j) + import_xchan($j); + $x = q("select * from hubloc left join xchan on xchan_hash = hubloc_hash where hubloc_addr = '%s' order by hubloc_id desc limit 1", + dbesc($address) + ); + } + } + if(! $x) { + logger('mod_zot: auth: unable to finger ' . $address); + + if($test) { + $ret['message'] .= 'no hubloc found for ' . $address . ' and probing failed.' . EOL; + json_return_and_die($ret); + } + + goaway($desturl); + } + + logger('mod_zot: auth request received from ' . $x[0]['hubloc_addr'] ); + + // check credentials and access + + // If they are already authenticated and haven't changed credentials, + // we can save an expensive network round trip and improve performance. + + $remote = remote_user(); + $result = null; + $remote_service_class = ''; + $remote_level = 0; + $remote_hub = $x[0]['hubloc_url']; + + // Also check that they are coming from the same site as they authenticated with originally. + + $already_authed = ((($remote) && ($x[0]['hubloc_hash'] == $remote) && ($x[0]['hubloc_url'] === $_SESSION['remote_hub'])) ? true : false); + + $j = array(); + + if(! $already_authed) { + + // Auth packets MUST use ultra top-secret hush-hush mode - e.g. the entire packet is encrypted using the site private key + // The actual channel sending the packet ($c[0]) is not important, but this provides a generic zot packet with a sender + // which can be verified + + $p = zot_build_packet($c[0],$type = 'auth_check', array(array('guid' => $x[0]['hubloc_guid'],'guid_sig' => $x[0]['hubloc_guid_sig'])), $x[0]['hubloc_sitekey'], $sec); + if($test) { + $ret['message'] .= 'auth check packet created using sitekey ' . $x[0]['hubloc_sitekey'] . EOL; + $ret['message'] .= 'packet contents: ' . $p . EOL; + } + + $result = zot_zot($x[0]['hubloc_callback'],$p); + + + if(! $result['success']) { + logger('mod_zot: auth_check callback failed.'); + if($test) { + $ret['message'] .= 'auth check request to your site returned .' . print_r($result, true) . EOL; + json_return_and_die($ret); + } + + goaway($desturl); + } + $j = json_decode($result['body'],true); + if(! $j) { + logger('mod_zot: auth_check json data malformed.'); + if($test) { + $ret['message'] .= 'json malformed: ' . $result['body'] . EOL; + json_return_and_die($ret); + } + } + } + + if($test) { + $ret['message'] .= 'auth check request returned .' . print_r($j, true) . EOL; + } + + if($already_authed || $j['success']) { + if($j['success']) { + // legit response, but we do need to check that this wasn't answered by a man-in-middle + if(! rsa_verify($sec . $x[0]['xchan_hash'],base64url_decode($j['confirm']),$x[0]['xchan_pubkey'])) { + logger('mod_zot: auth: final confirmation failed.'); + if($test) { + $ret['message'] .= 'final confirmation failed. ' . $sec . print_r($j,true) . print_r($x[0],true); + json_return_and_die($ret); + } + + goaway($desturl); + } + if(array_key_exists('service_class',$j)) + $remote_service_class = $j['service_class']; + if(array_key_exists('level',$j)) + $remote_level = $j['level']; + } + // everything is good... maybe + if(local_user()) { + + // tell them to logout if they're logged in locally as anything but the target remote account + // in which case just shut up because they don't need to be doing this at all. + + if($a->channel['channel_hash'] != $x[0]['xchan_hash']) { + logger('mod_zot: auth: already authenticated locally as somebody else.'); + notice( t('Remote authentication blocked. You are logged into this site locally. Please logout and retry.') . EOL); + if($test) { + $ret['message'] .= 'already logged in locally with a conflicting identity.' . EOL; + json_return_and_die($ret); + } + + } + goaway($desturl); + } + // log them in + + if($test) { + $ret['success'] = true; + $ret['message'] .= 'Authentication Success!' . EOL; + json_return_and_die($ret); + } + + + $_SESSION['authenticated'] = 1; + $_SESSION['visitor_id'] = $x[0]['xchan_hash']; + $_SESSION['my_url'] = $x[0]['xchan_url']; + $_SESSION['my_address'] = $address; + $_SESSION['remote_service_class'] = $remote_service_class; + $_SESSION['remote_level'] = $remote_level; + $_SESSION['remote_hub'] = $remote_hub; + + $arr = array('xchan' => $x[0], 'url' => $desturl, 'session' => $_SESSION); + call_hooks('magic_auth_success',$arr); + $a->set_observer($x[0]); + require_once('include/security.php'); + $a->set_groups(init_groups_visitor($_SESSION['visitor_id'])); + info(sprintf( t('Welcome %s. Remote authentication successful.'),$x[0]['xchan_name'])); + logger('mod_zot: auth success from ' . $x[0]['xchan_addr']); + q("update hubloc set hubloc_status = (hubloc_status | %d ) where hubloc_id = %d ", + intval(HUBLOC_WORKS), + intval($x[0]['hubloc_id']) + ); + + + } else { + if($test) { + $ret['message'] .= 'auth failure. ' . print_r($_REQUEST,true) . print_r($j,true) . EOL; + json_return_and_die($ret); + } + + logger('mod_zot: magic-auth failure - not authenticated: ' . $x[0]['xchan_addr']); + q("update hubloc set hubloc_status = (hubloc_status | %d ) where hubloc_id = %d ", + intval(HUBLOC_RECEIVE_ERROR), + intval($x[0]['hubloc_id']) + ); + } + + // FIXME - we really want to save the return_url in the session before we visit rmagic. + // This does however prevent a recursion if you visit rmagic directly, as it would otherwise send you back here again. + // But z_root() probably isn't where you really want to go. + + if($test) { + $ret['message'] .= 'auth failure fallthrough ' . print_r($_REQUEST,true) . print_r($j,true) . EOL; + json_return_and_die($ret); + } + + if(strstr($desturl,z_root() . '/rmagic')) + goaway(z_root()); + + goaway($desturl); + } + return; +} + + +/** + * @function post_post(&$a) + * zot communications and messaging + * + * Sender HTTP posts to this endpoint ($site/post typically) with 'data' parameter set to json zot message packet. + * This packet is optionally encrypted, which we will discover if the json has an 'iv' element. + * $contents => array( 'alg' => 'aes256cbc', 'iv' => initialisation vector, 'key' => decryption key, 'data' => encrypted data); + * $contents->iv and $contents->key are random strings encrypted with this site's RSA public key and then base64url encoded. + * Currently only 'aes256cbc' is used, but this is extensible should that algorithm prove inadequate. + * + * Once decrypted, one will find the normal json_encoded zot message packet. + * + * Defined packet types are: notify, purge, refresh, force_refresh, auth_check, ping, and pickup + * + * Standard packet: (used by notify, purge, refresh, force_refresh, and auth_check) + * + * { + * "type": "notify", + * "sender":{ + * "guid":"kgVFf_1...", + * "guid_sig":"PT9-TApzp...", + * "url":"http:\/\/podunk.edu", + * "url_sig":"T8Bp7j5...", + * }, + * "recipients": { optional recipient array }, + * "callback":"\/post", + * "version":1, + * "secret":"1eaa...", + * "secret_sig": "df89025470fac8..." + * } + * + * Signature fields are all signed with the sender channel private key and base64url encoded. + * Recipients are arrays of guid and guid_sig, which were previously signed with the recipients private + * key and base64url encoded and later obtained via channel discovery. Absence of recipients indicates + * a public message or visible to all potential listeners on this site. + * + * "pickup" packet: + * The pickup packet is sent in response to a notify packet from another site + * + * { + * "type":"pickup", + * "url":"http:\/\/example.com", + * "callback":"http:\/\/example.com\/post", + * "callback_sig":"teE1_fLI...", + * "secret":"1eaa...", + * "secret_sig":"O7nB4_..." + * } + * + * In the pickup packet, the sig fields correspond to the respective data element signed with this site's system + * private key and then base64url encoded. + * The "secret" is the same as the original secret from the notify packet. + * + * If verification is successful, a json structure is returned + * containing a success indicator and an array of type 'pickup'. + * Each pickup element contains the original notify request and a message field whose contents are + * dependent on the message type + * + * This JSON array is AES encapsulated using the site public key of the site that sent the initial zot pickup packet. + * Using the above example, this would be example.com. + * + * + * { + * "success":1, + * "pickup":{ + * "notify":{ + * "type":"notify", + * "sender":{ + * "guid":"kgVFf_...", + * "guid_sig":"PT9-TApz...", + * "url":"http:\/\/z.podunk.edu", + * "url_sig":"T8Bp7j5D..." + * }, + * "callback":"\/post", + * "version":1, + * "secret":"1eaa661..." + * }, + * "message":{ + * "type":"activity", + * "message_id":"10b049ce384cbb2da9467319bc98169ab36290b8bbb403aa0c0accd9cb072e76@podunk.edu", + * "message_top":"10b049ce384cbb2da9467319bc98169ab36290b8bbb403aa0c0accd9cb072e76@podunk.edu", + * "message_parent":"10b049ce384cbb2da9467319bc98169ab36290b8bbb403aa0c0accd9cb072e76@podunk.edu", + * "created":"2012-11-20 04:04:16", + * "edited":"2012-11-20 04:04:16", + * "title":"", + * "body":"Hi Nickordo", + * "app":"", + * "verb":"post", + * "object_type":"", + * "target_type":"", + * "permalink":"", + * "location":"", + * "longlat":"", + * "owner":{ + * "name":"Indigo", + * "address":"indigo@podunk.edu", + * "url":"http:\/\/podunk.edu", + * "photo":{ + * "mimetype":"image\/jpeg", + * "src":"http:\/\/podunk.edu\/photo\/profile\/m\/5" + * }, + * "guid":"kgVFf_...", + * "guid_sig":"PT9-TAp...", + * }, + * "author":{ + * "name":"Indigo", + * "address":"indigo@podunk.edu", + * "url":"http:\/\/podunk.edu", + * "photo":{ + * "mimetype":"image\/jpeg", + * "src":"http:\/\/podunk.edu\/photo\/profile\/m\/5" + * }, + * "guid":"kgVFf_...", + * "guid_sig":"PT9-TAp..." + * } + * } + * } + *} + * + * Currently defined message types are 'activity', 'mail', 'profile' and 'channel_sync', which each have + * different content schemas. + * + * Ping packet: + * A ping packet does not require any parameters except the type. It may or may not be encrypted. + * + * { + * "type": "ping" + * } + * + * On receipt of a ping packet a ping response will be returned: + * + * { + * "success" : 1, + * "site" { + * "url":"http:\/\/podunk.edu", + * "url_sig":"T8Bp7j5...", + * "sitekey": "-----BEGIN PUBLIC KEY----- + * MIICIjANBgkqhkiG9w0BAQE..." + * } + * } + * + * The ping packet can be used to verify that a site has not been re-installed, and to + * initiate corrective action if it has. The url_sig is signed with the site private key + * and base64url encoded - and this should verify with the enclosed sitekey. Failure to + * verify indicates the site is corrupt or otherwise unable to communicate using zot. + * This return packet is not otherwise verified, so should be compared with other + * results obtained from this site which were verified prior to taking action. For instance + * if you have one verified result with this signature and key, and other records for this + * url which have different signatures and keys, it indicates that the site was re-installed + * and corrective action may commence (remove or mark invalid any entries with different + * signatures). + * If you have no records which match this url_sig and key - no corrective action should + * be taken as this packet may have been returned by an imposter. + * + */ + function post_post(&$a) { - logger('mod_zot: ' . print_r($_REQUEST,true), LOGGER_DEBUG); - $ret = array('result' => false); + $encrypted_packet = false; + $ret = array('success' => false); $data = json_decode($_REQUEST['data'],true); - logger('mod_zot: data: ' . print_r($data,true), LOGGER_DATA); + + /** + * Many message packets will arrive encrypted. The existence of an 'iv' element + * tells us we need to unencapsulate the AES-256-CBC content using the site private key + */ if(array_key_exists('iv',$data)) { - $data = aes_unencapsulate($data,get_config('system','prvkey')); - logger('mod_zot: decrypt1: ' . $data); + $encrypted_packet = true; + $data = crypto_unencapsulate($data,get_config('system','prvkey')); + logger('mod_zot: decrypt1: ' . $data, LOGGER_DATA); $data = json_decode($data,true); } - logger('mod_zot: decoded data: ' . print_r($data,true), LOGGER_DATA); + if(! $data) { + + // possible Bleichenbacher's attack, just treat it as a + // message we have no handler for. It should fail a bit + // further along with "no hub". Our public key is public + // knowledge. There's no reason why anybody should get the + // encryption wrong unless they're fishing or hacking. If + // they're developing and made a goof, this can be discovered + // in the logs of the destination site. If they're fishing or + // hacking, the bottom line is we can't verify their hub. + // That's all we're going to tell them. + + $data = array('type' => 'bogus'); + } + $msgtype = ((array_key_exists('type',$data)) ? $data['type'] : ''); + if($msgtype === 'ping') { + + // 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); + } if($msgtype === 'pickup') { + /** + * 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('mod_zot: pickup: ' . $ret['message'], LOGGER_DEBUG); json_return_and_die($ret); } - $r = q("select hubloc_sitekey from hubloc where hubloc_url = '%s' and hubloc_callback = '%s' and hubloc_sitekey != '' limit 1", + $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']) ); @@ -44,23 +527,47 @@ function post_post(&$a) { logger('mod_zot: pickup: ' . $ret['message']); json_return_and_die($ret); } - // verify the url_sig - $sitekey = $r[0]['hubloc_sitekey']; - logger('sitekey: ' . $sitekey); - if(! rsa_verify($data['callback'],base64url_decode($data['callback_sig']),$sitekey)) { + 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(! rsa_verify($data['secret'],base64url_decode($data['secret_sig']),$sitekey)) { + 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, we've got a valid pickup. Grab everything for this host and send it. + /** + * 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']), @@ -72,10 +579,17 @@ function post_post(&$a) { 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: succesful pickup message received from ' . $data['callback'] . ' ' . count($r) . ' message(s) picked up', LOGGER_DEBUG); + $ret['success'] = true; $ret['pickup'] = array(); foreach($r as $rr) { @@ -86,34 +600,231 @@ function post_post(&$a) { ); } } - $encrypted = aes_encapsulate(json_encode($ret),$sitekey); + + $encrypted = crypto_encapsulate(json_encode($ret),$sitekey); json_return_and_die($encrypted); + + /** pickup: end */ } + + + + /** + * All other message types require us to verify the sender. This is a generic check, so we + * will do it once here and bail if anything goes wrong. + */ + if(array_key_exists('sender',$data)) { $sender = $data['sender']; } + /** Check if the sender is already verified here */ + $hub = zot_gethub($sender); + if(! $hub) { + + /** Have never seen this guid or this guid coming from this location. Check it and register it. */ + // (!!) this will validate the sender $result = zot_register_hub($sender); - if((! $result['success']) || (! zot_gethub($sender))) { + + if((! $result['success']) || (! ($hub = zot_gethub($sender)))) { $ret['message'] = 'Hub not available.'; logger('mod_zot: no hub'); json_return_and_die($ret); } } + + // 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 limit 1", + dbesc(datetime_convert()), + intval($hub['hubloc_id']) + ); + + // a dead hub came back to life - reset any tombstones we might have + + if($hub['hubloc_status'] & HUBLOC_OFFLINE) { + q("update hubloc set hubloc_status = (hubloc_status ^ %d) where hubloc_id = %d limit 1", + intval(HUBLOC_OFFLINE), + intval($hub['hubloc_id']) + ); + if($r[0]['hubloc_flags'] & HUBLOC_FLAGS_ORPHANCHECK) { + q("update hubloc set hubloc_flags = (hubloc_flags ^ %d) where hubloc_id = %d limit 1", + intval(HUBLOC_FLAGS_ORPHANCHECK), + intval($hub['hubloc_id']) + ); + } + q("update xchan set xchan_flags = (xchan_flags ^ %d) where (xchan_flags & %d) and xchan_hash = '%s' limit 1", + intval(XCHAN_FLAGS_ORPHAN), + intval(XCHAN_FLAGS_ORPHAN), + dbesc($hub['hubloc_hash']) + ); + } + + + + /** + * 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_flags = ( hubloc_flags | %d ) where hubloc_url = '%s' and hubloc_sitekey != '%s' ", + intval(HUBLOC_FLAGS_DELETED), + dbesc($hub['hubloc_url']), + dbesc($hub['hubloc_sitekey']) + ); + // TODO: check which hub is primary and take action if mismatched if(array_key_exists('recipients',$data)) $recipients = $data['recipients']; - if($msgtype === 'refresh') { + + if($msgtype === 'auth_check') { + + /** + * 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 = base64url_encode(hash('whirlpool',$arr['guid'] . $arr['guid_sig'], true)); + + // garbage collect any old unused notifications + q("delete from verify where type = 'auth' and created < UTC_TIMESTAMP() - INTERVAL 10 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 = base64url_encode(hash('whirlpool',$arr['guid'] . $arr['guid_sig'], true)); + $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 limit 1", + 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']; + json_return_and_die($ret); + + } + json_return_and_die($ret); + } + + + if($msgtype === 'purge') { + 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(base64url_encode(hash('whirlpool',$sender['guid'] . $sender['guid_sig'], true))) + ); + if($r) { + contact_remove($r[0]['channel_id'],$r[0]['abook_id']); + } + } + } + } + else { + // Unfriend everybody - basically this means the channel has committed suicide + $arr = $data['sender']; + $sender_hash = base64url_encode(hash('whirlpool',$arr['guid'] . $arr['guid_sig'], true)); + + require_once('include/Contact.php'); + remove_all_xchan_resources($sender_hash); + + $ret['success'] = true; + json_return_and_die($ret); + + } + } + + if(($msgtype === 'refresh') || ($msgtype === 'force_refresh')) { // 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) { @@ -131,7 +842,7 @@ function post_post(&$a) { 'xchan_guid' => $sender['guid'], 'xchan_guid_sig' => $sender['guid_sig'], 'hubloc_url' => $sender['url'] - ),$r[0]); + ),$r[0], (($msgtype === 'force_refresh') ? true : false)); } } else { @@ -142,9 +853,9 @@ function post_post(&$a) { 'xchan_guid' => $sender['guid'], 'xchan_guid_sig' => $sender['guid_sig'], 'hubloc_url' => $sender['url'] - ),null); + ),null,(($msgtype === 'force_refresh') ? true : false)); } - $ret['result'] = true; + $ret['success'] = true; json_return_and_die($ret); } @@ -160,11 +871,15 @@ function post_post(&$a) { $ret['delivery_report'] = $x; } - $ret['result'] = true; + $ret['success'] = true; json_return_and_die($ret); } -} + // catchall + json_return_and_die($ret); + + +} diff --git a/mod/probe.php b/mod/probe.php index f90728df2..8e0b60dcc 100644 --- a/mod/probe.php +++ b/mod/probe.php @@ -1,6 +1,5 @@ <?php -require_once('include/Scrape.php'); require_once('include/zot.php'); function probe_content(&$a) { @@ -16,11 +15,22 @@ function probe_content(&$a) { if(x($_GET,'addr')) { $channel = $a->get_channel(); $addr = trim($_GET['addr']); - $res = zot_finger($addr,$channel); + $res = zot_finger($addr,$channel,false); $o .= '<pre>'; - $j = json_decode($res['body'],true); + if($res['success']) + $j = json_decode($res['body'],true); + else { + $o .= sprintf( t('Fetching URL returns error: %1$s'),$res['error'] . "\r\n\r\n"); + $o .= "<strong>https connection failed. Trying again with auto failover to http.</strong>\r\n\r\n"; + $res = zot_finger($addr,$channel,true); + if($res['success']) + $j = json_decode($res['body'],true); + else + $o .= sprintf( t('Fetching URL returns error: %1$s'),$res['error'] . "\r\n\r\n"); + + } if($j && $j['permissions'] && $j['permissions']['iv']) - $j['permissions'] = json_decode(aes_unencapsulate($j['permissions'],$channel['channel_prvkey']),true); + $j['permissions'] = json_decode(crypto_unencapsulate($j['permissions'],$channel['channel_prvkey']),true); $o .= str_replace("\n",'<br />',print_r($j,true)); $o .= '</pre>'; } diff --git a/mod/profile.php b/mod/profile.php index 549536931..792bf34c5 100644 --- a/mod/profile.php +++ b/mod/profile.php @@ -1,16 +1,14 @@ -<?php - -function profile_init(&$a) { - - $a->page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . $a->get_baseurl() . '/feed/' . $which .'" />' . "\r\n" ; - -} +<?php /** @file */ +require_once('include/contact_widgets.php'); +require_once('include/items.php'); +require_once("include/bbcode.php"); +require_once('include/security.php'); +require_once('include/conversation.php'); +require_once('include/acl_selectors.php'); -function profile_aside(&$a) { - require_once('include/contact_widgets.php'); - require_once('include/items.php'); +function profile_init(&$a) { if(argc() > 1) $which = argv(1); @@ -20,100 +18,64 @@ function profile_aside(&$a) { return; } - $profile = 0; + $profile = ''; $channel = $a->get_channel(); if((local_user()) && (argc() > 2) && (argv(2) === 'view')) { $which = $channel['channel_address']; $profile = argv(1); + $r = q("select profile_guid from profile where id = %d and uid = %d limit 1", + intval($profile), + intval(local_user()) + ); + if(! $r) + $profile = ''; + $profile = $r[0]['profile_guid']; } + $a->page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . $a->get_baseurl() . '/feed/' . $which .'" />' . "\r\n" ; - $x = q("select channel_id as profile_uid from channel where channel_address = '%s' limit 1", - dbesc(argv(1)) - ); - if($x) { - $a->profile = $x[0]; - $channel_display = get_pconfig($a->profile['profile_uid'],'system','channel_format'); - if(! $channel_display) - profile_load($a,$which,$profile); - if($channel_display === 'full') - $a->page['template'] = 'full'; - else { - $a->set_widget('archive',posted_date_widget($a->get_baseurl(true) . '/channel/' . $a->profile['nickname'],$a->profile['profile_uid'],true)); - $a->set_widget('categories',categories_widget($a->get_baseurl(true) . '/channel/' . $a->profile['nickname'],$cat)); + if(! $profile) { + $x = q("select channel_id as profile_uid from channel where channel_address = '%s' limit 1", + dbesc(argv(1)) + ); + if($x) { + $a->profile = $x[0]; } } -} + + profile_load($a,$which,$profile); +} + function profile_content(&$a, $update = 0) { if(get_config('system','block_public') && (! get_account_id()) && (! remote_user())) { return login(); } - - require_once("include/bbcode.php"); - require_once('include/security.php'); - require_once('include/conversation.php'); - require_once('include/acl_selectors.php'); - require_once('include/items.php'); - $groups = array(); $tab = 'profile'; $o = ''; - if($a->profile['profile_uid'] == local_user()) { - nav_set_selected('home'); - } - - $contact = null; - $remote_contact = false; - - $contact_id = 0; - - if(is_array($_SESSION['remote'])) { - foreach($_SESSION['remote'] as $v) { - if($v['uid'] == $a->profile['profile_uid']) { - $contact_id = $v['cid']; - break; - } - } - } - - if($contact_id) { - $groups = init_groups_visitor($contact_id); - $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($contact_id), - intval($a->profile['profile_uid']) - ); - if(count($r)) { - $contact = $r[0]; - $remote_contact = true; - } + if(! (perm_is_allowed($a->profile['profile_uid'],get_observer_hash(), 'view_profile'))) { + notice( t('Permission denied.') . EOL); + return; } - if(! $remote_contact) { - if(local_user()) { - $contact_id = $_SESSION['cid']; - $contact = $a->contact; - } - } $is_owner = ((local_user()) && (local_user() == $a->profile['profile_uid']) ? true : false); - if($a->profile['hidewall'] && (! $is_owner) && (! $remote_contact)) { - notice( t('Access to this profile has been restricted.') . EOL); + if($a->profile['hidewall'] && (! $is_owner) && (! remote_user())) { + notice( t('Permission denied.') . EOL); return; } - $o .= profile_tabs($a, $is_owner, $a->profile['channel_address']); - require_once('include/profile_advanced.php'); $o .= advanced_profile($a); call_hooks('profile_advanced',$o); return $o; diff --git a/mod/profile_photo.php b/mod/profile_photo.php index e78d2ca6f..c587b9606 100644 --- a/mod/profile_photo.php +++ b/mod/profile_photo.php @@ -1,6 +1,64 @@ <?php -require_once("Photo.php"); +/* @file profile_photo.php + @brief Module-file with functions for handling of profile-photos + +*/ + +require_once('include/photo/photo_driver.php'); + +/* @brief Function for sync'ing permissions of profile-photos and their profile +* +* @param $profileid The id number of the profile to sync +* @return void +*/ + +function profile_photo_set_profile_perms($profileid = '') { + + $allowcid = ''; + if (x($profileid)) { + + $r = q("SELECT photo, profile_guid, id, is_default, uid FROM profile WHERE profile.id = %d OR profile.profile_guid = '%s' LIMIT 1", intval($profileid), dbesc($profileid)); + + } else { + + logger('Resetting permissions on default-profile-photo for user'.local_user()); + $r = q("SELECT photo, profile_guid, id, is_default, uid FROM profile WHERE profile.uid = %d AND is_default = 1 LIMIT 1", intval(local_user()) ); //If no profile is given, we update the default profile + } + + $profile = $r[0]; + if(x($profile['id']) && x($profile['photo'])) { + preg_match("@\w*(?=-\d*$)@i", $profile['photo'], $resource_id); + $resource_id = $resource_id[0]; + + if (intval($profile['is_default']) != 1) { + $r0 = q("SELECT channel_hash FROM channel WHERE channel_id = %d LIMIT 1", intval(local_user()) ); + $r1 = q("SELECT abook.abook_xchan FROM abook WHERE abook_profile = %d ", intval($profile['id'])); //Should not be needed in future. Catches old int-profile-ids. + $r2 = q("SELECT abook.abook_xchan FROM abook WHERE abook_profile = '%s'", dbesc($profile['profile_guid'])); + $allowcid = "<" . $r0[0]['channel_hash'] . ">"; + foreach ($r1 as $entry) { + $allowcid .= "<" . $entry['abook_xchan'] . ">"; + } + foreach ($r2 as $entry) { + $allowcid .= "<" . $entry['abook_xchan'] . ">"; + } + + q("UPDATE `photo` SET allow_cid = '%s' WHERE resource_id = '%s' AND uid = %d",dbesc($allowcid),dbesc($resource_id),intval($profile['uid'])); + + } else { + q("UPDATE `photo` SET allow_cid = '' WHERE profile = 1 AND uid = %d",intval($profile['uid'])); //Reset permissions on default profile picture to public + } + } + + return; +} + +/* @brief Initalize the profile-photo edit view + * + * @param $a Current application + * @return void + * + */ function profile_photo_init(&$a) { @@ -13,11 +71,16 @@ function profile_photo_init(&$a) { } +/* @brief Evaluate posted values + * + * @param $a Current application + * @return void + * + */ function profile_photo_post(&$a) { if(! local_user()) { - notice ( t('Permission denied.') . EOL ); return; } @@ -29,11 +92,11 @@ function profile_photo_post(&$a) { $is_default_profile = 1; if($_REQUEST['profile']) { - $r = q("select id, `is_default` from profile where id = %d and uid = %d limit 1", + $r = q("select id, is_default from profile where id = %d and uid = %d limit 1", intval($_REQUEST['profile']), intval(local_user()) ); - if(count($r) && (! intval($r[0]['is_default']))) + if(($r) && (! intval($r[0]['is_default']))) $is_default_profile = 0; } @@ -41,12 +104,12 @@ function profile_photo_post(&$a) { // phase 2 - we have finished cropping - if($a->argc != 2) { + if(argc() != 2) { notice( t('Image uploaded but image cropping failed.') . EOL ); return; } - $image_id = $a->argv[1]; + $image_id = argv(1); if(substr($image_id,-2,1) == '-') { $scale = substr($image_id,-1,1); @@ -59,45 +122,61 @@ function profile_photo_post(&$a) { $srcW = $_POST['xfinal'] - $srcX; $srcH = $_POST['yfinal'] - $srcY; - $r = q("SELECT * FROM `photo` WHERE `resource_id` = '%s' AND `uid` = %d AND `scale` = %d LIMIT 1", + $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND scale = %d LIMIT 1", dbesc($image_id), dbesc(local_user()), intval($scale)); - if(count($r)) { + if($r) { $base_image = $r[0]; - $im = new Photo($base_image['data'], $base_image['type']); + $im = photo_factory($base_image['data'], $base_image['type']); if($im->is_valid()) { + $im->cropImage(175,$srcX,$srcY,$srcW,$srcH); - $r = $im->store(local_user(), 0, $base_image['resource_id'],$base_image['filename'], - t('Profile Photos'), 4, $is_default_profile); + $aid = get_account_id(); + + $p = array('aid' => $aid, 'uid' => local_user(), 'resource_id' => $base_image['resource_id'], + 'filename' => $base_image['filename'], 'album' => t('Profile Photos')); - if($r === false) - notice ( sprintf(t('Image size reduction [%s] failed.'),"175") . EOL ); + $p['scale'] = 4; + $p['photo_flags'] = (($is_default_profile) ? PHOTO_PROFILE : PHOTO_NORMAL); + + $r1 = $im->save($p); $im->scaleImage(80); + $p['scale'] = 5; - $r = $im->store(local_user(), 0, $base_image['resource_id'],$base_image['filename'], - t('Profile Photos'), 5, $is_default_profile); + $r2 = $im->save($p); - if($r === false) - notice( sprintf(t('Image size reduction [%s] failed.'),"80") . EOL ); - $im->scaleImage(48); + $p['scale'] = 6; - $r = $im->store(local_user(), 0, $base_image['resource_id'],$base_image['filename'], - t('Profile Photos'), 6, $is_default_profile); + $r3 = $im->save($p); - if($r === false) - notice( sprintf(t('Image size reduction [%s] failed.'),"48") . EOL ); + if($r1 === false || $r2 === false || $r3 === false) { + // if one failed, delete them all so we can start over. + notice( t('Image resize failed.') . EOL ); + $x = q("delete from photo where resource_id = '%s' and uid = %d and scale >= 4 ", + dbesc($base_image['resource_id']), + local_user() + ); + return; + } // If setting for the default profile, unset the profile photo flag from any other photos I own if($is_default_profile) { - $r = q("UPDATE `photo` SET `profile` = 0 WHERE `profile` = 1 AND `resource_id` != '%s' AND `uid` = %d", + $r = q("UPDATE photo SET profile = 0 WHERE profile = 1 AND resource_id != '%s' AND `uid` = %d", + dbesc($base_image['resource_id']), + intval(local_user()) + ); + $r = q("UPDATE photo SET photo_flags = ( photo_flags ^ %d ) WHERE ( photo_flags & %d ) + AND resource_id != '%s' AND `uid` = %d", + intval(PHOTO_PROFILE), + intval(PHOTO_PROFILE), dbesc($base_image['resource_id']), intval(local_user()) ); @@ -124,10 +203,13 @@ function profile_photo_post(&$a) { ); info( t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL); - // Update global directory in background - $url = $a->get_baseurl() . '/channel/' . $a->user['nickname']; - if($url && strlen(get_config('system','directory_submit_url'))) - proc_run('php',"include/directory.php","$url"); + + // Update directory in background + proc_run('php',"include/directory.php",$channel['channel_id']); + + // Now copy profile-permissions to pictures, to prevent privacyleaks by automatically created folder 'Profile Pictures' + + profile_photo_set_profile_perms($_REQUEST['profile']); } else @@ -153,7 +235,7 @@ function profile_photo_post(&$a) { } $imagedata = @file_get_contents($src); - $ph = new Photo($imagedata, $filetype); + $ph = photo_factory($imagedata, $filetype); if(! $ph->is_valid()) { notice( t('Unable to process image.') . EOL ); @@ -166,6 +248,13 @@ function profile_photo_post(&$a) { } +/* @brief Generate content of profile-photo view + * + * @param $a Current application + * @return void + * + */ + if(! function_exists('profile_photo_content')) { function profile_photo_content(&$a) { @@ -175,6 +264,8 @@ function profile_photo_content(&$a) { return; } + $channel = $a->get_channel(); + $newuser = false; if(argc() == 2 && argv(1) === 'new') @@ -189,13 +280,14 @@ function profile_photo_content(&$a) { // check_form_security_token_redirectOnErr('/profile_photo', 'profile_photo'); $resource_id = argv(2); - //die(":".local_user()); - $r=q("SELECT * FROM `photo` WHERE `uid` = %d AND `resource_id` = '%s' ORDER BY `scale` ASC", + + + $r = q("SELECT id, album, scale FROM photo WHERE uid = %d AND resource_id = '%s' ORDER BY scale ASC", intval(local_user()), dbesc($resource_id) - ); - if (!count($r)){ - notice( t('Permission denied.') . EOL ); + ); + if(! $r) { + notice( t('Photo not available.') . EOL ); return; } $havescale = false; @@ -204,65 +296,85 @@ function profile_photo_content(&$a) { $havescale = true; } - // set an already uloaded photo as profile photo - // if photo is in 'Profile Photos', change it in db - if (($r[0]['album']== t('Profile Photos')) && ($havescale)){ - $r=q("UPDATE `photo` SET `profile`=0 WHERE `profile`=1 AND `uid`=%d", + // set an already loaded photo as profile photo + + if(($r[0]['album'] == t('Profile Photos')) && ($havescale)) { + // unset any existing profile photos + $r = q("UPDATE photo SET profile = 0 WHERE profile = 1 AND uid = %d", intval(local_user())); - - $r=q("UPDATE `photo` SET `profile`=1 WHERE `uid` = %d AND `resource_id` = '%s'", + $r = q("UPDATE photo SET photo_flags = (photo_flags ^ %d ) WHERE (photo_flags & %d ) AND uid = %d", + intval(PHOTO_PROFILE), + intval(PHOTO_PROFILE), + intval(local_user())); + + // set all sizes of this one as profile photos + $r = q("UPDATE photo SET profile = 1 WHERE uid = %d AND resource_id = '%s'", intval(local_user()), dbesc($resource_id) ); - - $r = q("UPDATE `contact` SET `avatar_date` = '%s' WHERE `self` = 1 AND `uid` = %d LIMIT 1", + + $r = q("UPDATE photo SET photo_flags = ( photo_flags | %d ) WHERE uid = %d AND resource_id = '%s'", + intval(PHOTO_PROFILE), + intval(local_user()), + dbesc($resource_id) + ); + + $r = q("UPDATE xchan set xchan_photo_date = '%s' + where xchan_hash = '%s' limit 1", dbesc(datetime_convert()), - intval(local_user()) + dbesc($channel['xchan_hash']) ); - - // Update global directory in background - $url = $_SESSION['my_url']; - if($url && strlen(get_config('system','directory_submit_url'))) - proc_run('php',"include/directory.php","$url"); - + + profile_photo_set_profile_perms(); //Reset default photo permissions to public + proc_run('php','include/directory.php',local_user()); goaway($a->get_baseurl() . '/profiles'); - return; // NOTREACHED } - $ph = new Photo($r[0]['data'], $r[0]['type']); + + $r = q("SELECT `data`, `type` FROM photo WHERE id = %d and uid = %d limit 1", + intval($r[0]['id']), + intval(local_user()) + + ); + if(! $r) { + notice( t('Photo not available.') . EOL ); + return; + } + + $ph = photo_factory($r[0]['data'], $r[0]['type']); + // go ahead as if we have just uploaded a new photo to crop profile_photo_crop_ui_head($a, $ph); - // go ahead as we have jus uploaded a new photo to crop } - $profiles = q("select `id`,`profile_name` as `name`,`is_default` as `default` from profile where uid = %d", + $profiles = q("select id, profile_name as name, is_default from profile where uid = %d", intval(local_user()) ); + if(! x($a->data,'imagecrop')) { - if(! x($a->config,'imagecrop')) { - $tpl = get_markup_template('profile_photo.tpl'); $o .= replace_macros($tpl,array( - '$user' => $a->user['nickname'], + '$user' => $a->channel['channel_address'], '$lbl_upfile' => t('Upload File:'), '$lbl_profiles' => t('Select a profile:'), '$title' => t('Upload Profile Photo'), '$submit' => t('Upload'), '$profiles' => $profiles, '$form_security_token' => get_form_security_token("profile_photo"), - '$select' => sprintf('%s %s', t('or'), ($newuser) ? '<a href="' . $a->get_baseurl() . '">' . t('skip this step') . '</a>' : '<a href="'. $a->get_baseurl() . '/photos/' . $a->user['nickname'] . '">' . t('select a photo from your photo albums') . '</a>') +// FIXME - yuk + '$select' => sprintf('%s %s', t('or'), ($newuser) ? '<a href="' . $a->get_baseurl() . '">' . t('skip this step') . '</a>' : '<a href="'. $a->get_baseurl() . '/photos/' . $a->channel['channel_address'] . '">' . t('select a photo from your photo albums') . '</a>') )); return $o; } else { - $filename = $a->config['imagecrop'] . '-' . $a->config['imagecrop_resolution'] . '.'.$a->config['imagecrop_ext']; - $resolution = $a->config['imagecrop_resolution']; + $filename = $a->data['imagecrop'] . '-' . $a->data['imagecrop_resolution'] . '.' . $a->data['imagecrop_ext']; + $resolution = $a->data['imagecrop_resolution']; $tpl = get_markup_template("cropbody.tpl"); $o .= replace_macros($tpl,array( '$filename' => $filename, '$profile' => intval($_REQUEST['profile']), - '$resource' => $a->config['imagecrop'] . '-' . $a->config['imagecrop_resolution'], + '$resource' => $a->data['imagecrop'] . '-' . $a->data['imagecrop_resolution'], '$image_url' => $a->get_baseurl() . '/photo/' . $filename, '$title' => t('Crop Image'), '$desc' => t('Please adjust the image cropping for optimum viewing.'), @@ -275,30 +387,39 @@ function profile_photo_content(&$a) { return; // NOTREACHED }} +/* @brief Generate the UI for photo-cropping + * + * @param $a Current application + * @param $ph Photo-Factory + * @return void + * + */ + if(! function_exists('profile_photo_crop_ui_head')) { function profile_photo_crop_ui_head(&$a, $ph){ + $max_length = get_config('system','max_image_length'); if(! $max_length) $max_length = MAX_IMAGE_LENGTH; if($max_length > 0) $ph->scaleImage($max_length); - $width = $ph->getWidth(); + $width = $ph->getWidth(); $height = $ph->getHeight(); if($width < 175 || $height < 175) { $ph->scaleImageUp(200); - $width = $ph->getWidth(); + $width = $ph->getWidth(); $height = $ph->getHeight(); } $hash = photo_new_resource(); - - $smallest = 0; - $r = $ph->store(local_user(), 0 , $hash, $filename, t('Profile Photos'), 0 ); + $p = array('aid' => get_account_id(), 'uid' => local_user(), 'resource_id' => $hash, + 'filename' => $filename, 'album' => t('Profile Photos'), 'scale' => 0); + $r = $ph->save($p); if($r) info( t('Image uploaded successfully.') . EOL ); @@ -307,18 +428,20 @@ function profile_photo_crop_ui_head(&$a, $ph){ if($width > 640 || $height > 640) { $ph->scaleImage(640); - $r = $ph->store(local_user(), 0 , $hash, $filename, t('Profile Photos'), 1 ); - + $p['scale'] = 1; + + $r = $ph->save($p); + if($r === false) notice( sprintf(t('Image size reduction [%s] failed.'),"640") . EOL ); else $smallest = 1; } - $a->config['imagecrop'] = $hash; - $a->config['imagecrop_resolution'] = $smallest; - $a->config['imagecrop_ext'] = $ph->getExt(); - $a->page['htmlhead'] .= get_markup_template("crophead.tpl"); + $a->data['imagecrop'] = $hash; + $a->data['imagecrop_resolution'] = $smallest; + $a->data['imagecrop_ext'] = $ph->getExt(); + $a->page['htmlhead'] .= replace_macros(get_markup_template("crophead.tpl"), array()); return; }} diff --git a/mod/profiles.php b/mod/profiles.php index 37be9bd08..2e91db600 100644 --- a/mod/profiles.php +++ b/mod/profiles.php @@ -1,6 +1,151 @@ <?php +function profiles_init(&$a) { + + nav_set_selected('profiles'); + + if(! local_user()) { + return; + } + + if((argc() > 2) && (argv(1) === "drop") && intval(argv(2))) { + $r = q("SELECT * FROM `profile` WHERE `id` = %d AND `uid` = %d AND `is_default` = 0 LIMIT 1", + intval($a->argv[2]), + intval(local_user()) + ); + if(! count($r)) { + notice( t('Profile not found.') . EOL); + goaway($a->get_baseurl(true) . '/profiles'); + return; // NOTREACHED + } + $profile_guid = $r['profile_guid']; + + check_form_security_token_redirectOnErr('/profiles', 'profile_drop', 't'); + + // move every contact using this profile as their default to the user default + + $r = q("UPDATE abook SET abook_profile = (SELECT profile_guid AS FROM profile WHERE is_default = 1 AND uid = %d LIMIT 1) WHERE abook_profile = '%s' AND abook_channel = %d ", + intval(local_user()), + dbesc($profile_guid), + intval(local_user()) + ); + $r = q("DELETE FROM `profile` WHERE `id` = %d AND `uid` = %d LIMIT 1", + intval(argv(2)), + intval(local_user()) + ); + if($r) + info( t('Profile deleted.') . EOL); + + goaway($a->get_baseurl(true) . '/profiles'); + return; // NOTREACHED + } + + + + + + if((argc() > 1) && (argv(1) === 'new')) { + +// check_form_security_token_redirectOnErr('/profiles', 'profile_new', 't'); + + $r0 = q("SELECT `id` FROM `profile` WHERE `uid` = %d", + intval(local_user())); + $num_profiles = count($r0); + + $name = t('Profile-') . ($num_profiles + 1); + + $r1 = q("SELECT `name`, `photo`, `thumb` FROM `profile` WHERE `uid` = %d AND `is_default` = 1 LIMIT 1", + intval(local_user())); + + $r2 = q("INSERT INTO `profile` (`aid`, `uid` , `profile_guid`, `profile_name` , `name`, `photo`, `thumb`) + VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s' )", + intval(get_account_id()), + intval(local_user()), + dbesc(random_string()), + dbesc($name), + dbesc($r1[0]['name']), + dbesc($r1[0]['photo']), + dbesc($r1[0]['thumb']) + ); + + $r3 = q("SELECT `id` FROM `profile` WHERE `uid` = %d AND `profile_name` = '%s' LIMIT 1", + intval(local_user()), + dbesc($name) + ); + + info( t('New profile created.') . EOL); + if(count($r3) == 1) + goaway($a->get_baseurl(true) . '/profiles/' . $r3[0]['id']); + + goaway($a->get_baseurl(true) . '/profiles'); + } + + if((argc() > 2) && (argv(1) === 'clone')) { + + check_form_security_token_redirectOnErr('/profiles', 'profile_clone', 't'); + + $r0 = q("SELECT `id` FROM `profile` WHERE `uid` = %d", + intval(local_user())); + $num_profiles = count($r0); + + $name = t('Profile-') . ($num_profiles + 1); + $r1 = q("SELECT * FROM `profile` WHERE `uid` = %d AND `id` = %d LIMIT 1", + intval(local_user()), + intval($a->argv[2]) + ); + if(! count($r1)) { + notice( t('Profile unavailable to clone.') . EOL); + $a->error = 404; + return; + } + unset($r1[0]['id']); + $r1[0]['is_default'] = 0; + $r1[0]['publish'] = 0; + $r1[0]['profile_name'] = dbesc($name); + $r1[0]['profile_guid'] = dbesc(random_string()); + + dbesc_array($r1[0]); + + $r2 = dbq("INSERT INTO `profile` (`" + . implode("`, `", array_keys($r1[0])) + . "`) VALUES ('" + . implode("', '", array_values($r1[0])) + . "')" ); + + $r3 = q("SELECT `id` FROM `profile` WHERE `uid` = %d AND `profile_name` = '%s' LIMIT 1", + intval(local_user()), + dbesc($name) + ); + info( t('New profile created.') . EOL); + if(count($r3) == 1) + goaway($a->get_baseurl(true) . '/profiles/' . $r3[0]['id']); + + goaway($a->get_baseurl(true) . '/profiles'); + + return; // NOTREACHED + } + + + // Run profile_load() here to make sure the theme is set before + // we start loading content + if((argc() > 1) && (intval(argv(1)))) { + $r = q("SELECT * FROM `profile` WHERE `id` = %d AND `uid` = %d LIMIT 1", + intval($a->argv[1]), + intval(local_user()) + ); + if(! count($r)) { + notice( t('Profile not found.') . EOL); + $a->error = 404; + return; + } + + $chan = $a->get_channel(); + + profile_load($a,$chan['channel_address'],$r[0]['id']); + } +} + function profiles_post(&$a) { if(! local_user()) { @@ -44,31 +189,36 @@ function profiles_post(&$a) { $day = intval($_POST['day']); if(($day > $mtab[$month]) || ($day < 0)) $day = 0; + +// if($year && (! ($month && $day))) { +// $month = 1; $day = 1; +// } + $dob = '0000-00-00'; $dob = sprintf('%04d-%02d-%02d',$year,$month,$day); - $name = notags(trim($_POST['name'])); + $name = escape_tags(trim($_POST['name'])); if($orig[0]['name'] != $name) $namechanged = true; - $pdesc = notags(trim($_POST['pdesc'])); - $gender = notags(trim($_POST['gender'])); - $address = notags(trim($_POST['address'])); - $locality = notags(trim($_POST['locality'])); - $region = notags(trim($_POST['region'])); - $postal_code = notags(trim($_POST['postal_code'])); - $country_name = notags(trim($_POST['country_name'])); - $keywords = notags(trim($_POST['keywords'])); - $marital = notags(trim($_POST['marital'])); - $howlong = notags(trim($_POST['howlong'])); - $sexual = notags(trim($_POST['sexual'])); - $homepage = notags(trim($_POST['homepage'])); - $hometown = notags(trim($_POST['hometown'])); - $politic = notags(trim($_POST['politic'])); - $religion = notags(trim($_POST['religion'])); + $pdesc = escape_tags(trim($_POST['pdesc'])); + $gender = escape_tags(trim($_POST['gender'])); + $address = escape_tags(trim($_POST['address'])); + $locality = escape_tags(trim($_POST['locality'])); + $region = escape_tags(trim($_POST['region'])); + $postal_code = escape_tags(trim($_POST['postal_code'])); + $country_name = escape_tags(trim($_POST['country_name'])); + $keywords = escape_tags(trim($_POST['keywords'])); + $marital = escape_tags(trim($_POST['marital'])); + $howlong = escape_tags(trim($_POST['howlong'])); + $sexual = escape_tags(trim($_POST['sexual'])); + $homepage = escape_tags(trim($_POST['homepage'])); + $hometown = escape_tags(trim($_POST['hometown'])); + $politic = escape_tags(trim($_POST['politic'])); + $religion = escape_tags(trim($_POST['religion'])); $likes = fix_mce_lf(escape_tags(trim($_POST['likes']))); $dislikes = fix_mce_lf(escape_tags(trim($_POST['dislikes']))); @@ -76,6 +226,7 @@ function profiles_post(&$a) { $about = fix_mce_lf(escape_tags(trim($_POST['about']))); $interest = fix_mce_lf(escape_tags(trim($_POST['interest']))); $contact = fix_mce_lf(escape_tags(trim($_POST['contact']))); + $channels = fix_mce_lf(escape_tags(trim($_POST['channels']))); $music = fix_mce_lf(escape_tags(trim($_POST['music']))); $book = fix_mce_lf(escape_tags(trim($_POST['book']))); $tv = fix_mce_lf(escape_tags(trim($_POST['tv']))); @@ -86,7 +237,7 @@ function profiles_post(&$a) { $hide_friends = (($_POST['hide_friends'] == 1) ? 1: 0); - $with = ((x($_POST,'with')) ? notags(trim($_POST['with'])) : ''); + $with = ((x($_POST,'with')) ? escape_tags(trim($_POST['with'])) : ''); if(! strlen($howlong)) $howlong = '0000-00-00 00:00:00'; @@ -105,35 +256,23 @@ function profiles_post(&$a) { if(strpos($lookup,'@') === 0) $lookup = substr($lookup,1); $lookup = str_replace('_',' ', $lookup); - if(strpos($lookup,'@') || (strpos($lookup,'http://'))) { - $newname = $lookup; - $links = @lrdd($lookup); - if(count($links)) { - foreach($links as $link) { - if($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page') { - $prf = $link['@attributes']['href']; - } - } - } - } - else { - $newname = $lookup; - - $r = q("SELECT * FROM `contact` WHERE `name` = '%s' AND `uid` = %d LIMIT 1", - dbesc($newname), + $newname = $lookup; + + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash WHERE xchan_name = '%s' AND abook_channel = %d LIMIT 1", + dbesc($newname), + intval(local_user()) + ); + if(! $r) { + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash WHERE xchan_addr = '%s' AND abook_channel = %d LIMIT 1", + dbesc($lookup . '@%'), intval(local_user()) ); - if(! $r) { - $r = q("SELECT * FROM `contact` WHERE `nick` = '%s' AND `uid` = %d LIMIT 1", - dbesc($lookup), - intval(local_user()) - ); - } - if(count($r)) { - $prf = $r[0]['url']; - $newname = $r[0]['name']; - } } + if($r) { + $prf = $r[0]['xchan_url']; + $newname = $r[0]['xchan_name']; + } + if($prf) { $with = str_replace($lookup,'<a href="' . $prf . '">' . $newname . '</a>', $with); @@ -237,6 +376,7 @@ function profiles_post(&$a) { `about` = '%s', `interest` = '%s', `contact` = '%s', + `channels` = '%s', `music` = '%s', `book` = '%s', `tv` = '%s', @@ -270,6 +410,7 @@ function profiles_post(&$a) { dbesc($about), dbesc($interest), dbesc($contact), + dbesc($channels), dbesc($music), dbesc($book), dbesc($tv), @@ -278,17 +419,26 @@ function profiles_post(&$a) { dbesc($work), dbesc($education), intval($hide_friends), - intval($a->argv[1]), + intval(argv(1)), intval(local_user()) ); if($r) info( t('Profile updated.') . EOL); + $r = q("select * from profile where id = %d and uid = %d limit 1", + intval(argv(1)), + intval(local_user()) + ); + if($r) { + require_once('include/zot.php'); + build_sync_packet(local_user(),array('profile' => $r)); + } + $channel = $a->get_channel(); if($namechanged && $is_default) { - $r = q("UPDATE xchan SET xchan_name = '%s', xchan_name_date` = '%s' WHERE xchan_hash = '%s' limit 1", + $r = q("UPDATE xchan SET xchan_name = '%s', xchan_name_date = '%s' WHERE xchan_hash = '%s' limit 1", dbesc($name), dbesc(datetime_convert()), dbesc($channel['xchan_hash']) @@ -307,130 +457,12 @@ function profiles_post(&$a) { function profiles_content(&$a) { $o = ''; - nav_set_selected('profiles'); if(! local_user()) { notice( t('Permission denied.') . EOL); return; } - if((argc() > 2) && (argv(1) === "drop") && intval(argv(2))) { - $r = q("SELECT * FROM `profile` WHERE `id` = %d AND `uid` = %d AND `is_default` = 0 LIMIT 1", - intval($a->argv[2]), - intval(local_user()) - ); - if(! count($r)) { - notice( t('Profile not found.') . EOL); - goaway($a->get_baseurl(true) . '/profiles'); - return; // NOTREACHED - } - $profile_guid = $r['profile_guid']; - - check_form_security_token_redirectOnErr('/profiles', 'profile_drop', 't'); - - // move every contact using this profile as their default to the user default - - $r = q("UPDATE abook SET abook_profile = (SELECT profile_guid AS FROM profile WHERE is_default = 1 AND uid = %d LIMIT 1) WHERE abook_profile = '%s' AND abook_channel = %d ", - intval(local_user()), - dbesc($profile_guid), - intval(local_user()) - ); - $r = q("DELETE FROM `profile` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval(argv(2)), - intval(local_user()) - ); - if($r) - info( t('Profile deleted.') . EOL); - - goaway($a->get_baseurl(true) . '/profiles'); - return; // NOTREACHED - } - - - - - - if((argc() > 1) && (argv(1) === 'new')) { - - check_form_security_token_redirectOnErr('/profiles', 'profile_new', 't'); - - $r0 = q("SELECT `id` FROM `profile` WHERE `uid` = %d", - intval(local_user())); - $num_profiles = count($r0); - - $name = t('Profile-') . ($num_profiles + 1); - - $r1 = q("SELECT `name`, `photo`, `thumb` FROM `profile` WHERE `uid` = %d AND `is_default` = 1 LIMIT 1", - intval(local_user())); - - $r2 = q("INSERT INTO `profile` (`aid`, `uid` , `profile_guid`, `profile_name` , `name`, `photo`, `thumb`) - VALUES ( %d, '%s', '%s', '%s', '%s' )", - intval(get_account_id()), - intval(local_user()), - dbesc(random_string()), - dbesc($name), - dbesc($r1[0]['name']), - dbesc($r1[0]['photo']), - dbesc($r1[0]['thumb']) - ); - - $r3 = q("SELECT `id` FROM `profile` WHERE `uid` = %d AND `profile_name` = '%s' LIMIT 1", - intval(local_user()), - dbesc($name) - ); - - info( t('New profile created.') . EOL); - if(count($r3) == 1) - goaway($a->get_baseurl(true) . '/profiles/' . $r3[0]['id']); - - goaway($a->get_baseurl(true) . '/profiles'); - } - - if((argc() > 2) && (argv(1) === 'clone')) { - - check_form_security_token_redirectOnErr('/profiles', 'profile_clone', 't'); - - $r0 = q("SELECT `id` FROM `profile` WHERE `uid` = %d", - intval(local_user())); - $num_profiles = count($r0); - - $name = t('Profile-') . ($num_profiles + 1); - $r1 = q("SELECT * FROM `profile` WHERE `uid` = %d AND `id` = %d LIMIT 1", - intval(local_user()), - intval($a->argv[2]) - ); - if(! count($r1)) { - notice( t('Profile unavailable to clone.') . EOL); - return; - } - unset($r1[0]['id']); - $r1[0]['is_default'] = 0; - $r1[0]['publish'] = 0; - $r1[0]['profile_name'] = dbesc($name); - $r1[0]['profile_guid'] = dbesc(random_string()); - - dbesc_array($r1[0]); - - $r2 = dbq("INSERT INTO `profile` (`" - . implode("`, `", array_keys($r1[0])) - . "`) VALUES ('" - . implode("', '", array_values($r1[0])) - . "')" ); - - $r3 = q("SELECT `id` FROM `profile` WHERE `uid` = %d AND `profile_name` = '%s' LIMIT 1", - intval(local_user()), - dbesc($name) - ); - info( t('New profile created.') . EOL); - if(count($r3) == 1) - goaway($a->get_baseurl(true) . '/profiles/' . $r3[0]['id']); - - goaway($a->get_baseurl(true) . '/profiles'); - - return; // NOTREACHED - } - - if((argc() > 1) && (intval(argv(1)))) { $r = q("SELECT * FROM `profile` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($a->argv[1]), @@ -441,10 +473,6 @@ function profiles_content(&$a) { return; } - $chan = $a->get_channel(); - - profile_load($a,$chan['channel_address'],$r[0]['id']); - require_once('include/profile_selectors.php'); @@ -482,6 +510,7 @@ function profiles_content(&$a) { '$profile_drop_link' => 'profiles/drop/' . $r[0]['id'] . '?t=' . get_form_security_token("profile_drop"), + '$guid' => $r[0]['profile_guid'], '$banner' => t('Edit Profile Details'), '$submit' => t('Submit'), '$viewprof' => t('View this profile'), @@ -516,6 +545,7 @@ function profiles_content(&$a) { '$lbl_about' => t('Tell us about yourself...'), '$lbl_hobbies' => t('Hobbies/Interests'), '$lbl_social' => t('Contact information and Social Networks'), + '$lbl_channels' => t('My other channels'), '$lbl_music' => t('Musical interests'), '$lbl_book' => t('Books, literature'), '$lbl_tv' => t('Television'), @@ -540,7 +570,7 @@ function profiles_content(&$a) { '$age' => ((intval($r[0]['dob'])) ? '(' . t('Age: ') . age($r[0]['dob'],$a->user['timezone'],$a->user['timezone']) . ')' : ''), '$gender' => gender_selector($r[0]['gender']), '$marital' => marital_selector($r[0]['marital']), - '$with' => strip_tags($r[0]['with']), + '$with' => $r[0]['with'], '$howlong' => ($r[0]['howlong'] === '0000-00-00 00:00:00' ? '' : datetime_convert('UTC',date_default_timezone_get(),$r[0]['howlong'])), '$sexual' => sexpref_selector($r[0]['sexual']), '$about' => $r[0]['about'], @@ -559,7 +589,8 @@ function profiles_content(&$a) { '$romance' => $r[0]['romance'], '$work' => $r[0]['work'], '$education' => $r[0]['education'], - '$contact' => $r[0]['contact'] + '$contact' => $r[0]['contact'], + '$channels' => $r[0]['channels'], )); $arr = array('profile' => $r[0], 'entry' => $o); @@ -576,6 +607,8 @@ function profiles_content(&$a) { $tpl_header = get_markup_template('profile_listing_header.tpl'); $o .= replace_macros($tpl_header,array( '$header' => t('Edit/Manage Profiles'), + '$addstuff' => t('Add profile things'), + '$stuff_desc' => t('Include desirable objects in your profile'), '$chg_photo' => t('Change profile photo'), '$cr_new' => t('Create New Profile'), '$cr_new_link' => 'profiles/new?t=' . get_form_security_token("profile_new") @@ -586,7 +619,7 @@ function profiles_content(&$a) { foreach($r as $rr) { $o .= replace_macros($tpl, array( - '$photo' => $a->get_cached_avatar_image($rr['thumb']), + '$photo' => $rr['thumb'], '$id' => $rr['id'], '$alt' => t('Profile Image'), '$profile_name' => $rr['profile_name'], diff --git a/mod/profperm.php b/mod/profperm.php index b31dfc128..197062936 100644 --- a/mod/profperm.php +++ b/mod/profperm.php @@ -1,12 +1,16 @@ <?php +require_once('include/Contact.php'); + function profperm_init(&$a) { if(! local_user()) return; - $which = $a->user['nickname']; - $profile = $a->argv[1]; + $channel = $a->get_channel(); + $which = $channel['channel_address']; + + $profile = $a->argv[1]; profile_load($a,$which,$profile); @@ -21,7 +25,7 @@ function profperm_content(&$a) { } - if($a->argc < 2) { + if(argc() < 2) { notice( t('Invalid profile identifier.') . EOL ); return; } @@ -35,59 +39,64 @@ function profperm_content(&$a) { $switchtotext = 400; - if(($a->argc > 2) && intval($a->argv[1]) && intval($a->argv[2])) { - $r = q("SELECT `id` FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `self` = 0 - AND `network` = 'dfrn' AND `id` = %d AND `uid` = %d LIMIT 1", - intval($a->argv[2]), + if((argc() > 2) && intval(argv(1)) && intval(argv(2))) { + $r = q("SELECT abook_id FROM abook WHERE abook_id = %d and abook_channel = %d limit 1", + intval(argv(2)), intval(local_user()) ); - if(count($r)) - $change = intval($a->argv[2]); + if($r) + $change = intval(argv(2)); } - if(($a->argc > 1) && (intval($a->argv[1]))) { + if((argc() > 1) && (intval(argv(1)))) { $r = q("SELECT * FROM `profile` WHERE `id` = %d AND `uid` = %d AND `is_default` = 0 LIMIT 1", - intval($a->argv[1]), + intval(argv(1)), intval(local_user()) ); - if(! count($r)) { + if(! $r) { notice( t('Invalid profile identifier.') . EOL ); return; } + $profile = $r[0]; - $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `profile_id` = %d", + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d AND abook_profile = '%s'", intval(local_user()), - intval($a->argv[1]) + dbesc($profile['profile_guid']) ); $ingroup = array(); - if(count($r)) + if($r) foreach($r as $member) - $ingroup[] = $member['id']; + $ingroup[] = $member['abook_id']; $members = $r; if($change) { if(in_array($change,$ingroup)) { - q("UPDATE `contact` SET `profile_id` = 0 WHERE `id` = %d AND `uid` = %d LIMIT 1", + q("UPDATE abook SET abook_profile = '' WHERE abook_id = %d AND abook_channel = %d LIMIT 1", intval($change), intval(local_user()) ); } else { - q("UPDATE `contact` SET `profile_id` = %d WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($a->argv[1]), + q("UPDATE abook SET abook_profile = '%s' WHERE abook_id = %d AND abook_channel = %d LIMIT 1", + dbesc($profile['profile_guid']), intval($change), intval(local_user()) ); } - $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `profile_id` = %d", + + //Time to update the permissions on the profile-pictures as well + require_once('mod/profile_photo.php'); + profile_photo_set_profile_perms($profile['id']); + + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d AND abook_profile = '%s'", intval(local_user()), - intval($a->argv[1]) + dbesc($profile['profile_guid']) ); $members = $r; @@ -95,7 +104,7 @@ function profperm_content(&$a) { $ingroup = array(); if(count($r)) foreach($r as $member) - $ingroup[] = $member['id']; + $ingroup[] = $member['abook_id']; } $o .= '<h2>' . t('Profile Visibility Editor') . '</h2>'; @@ -107,9 +116,9 @@ function profperm_content(&$a) { } $o .= '<div id="prof-update-wrapper">'; - if($change) + if($change) $o = ''; - + $o .= '<div id="prof-members-title">'; $o .= '<h3>' . t('Visible To') . '</h3>'; $o .= '</div>'; @@ -118,8 +127,8 @@ function profperm_content(&$a) { $textmode = (($switchtotext && (count($members) > $switchtotext)) ? true : false); foreach($members as $member) { - if($member['url']) { - $member['click'] = 'profChangeMember(' . $profile['id'] . ',' . $member['id'] . '); return true;'; + if($member['xchan_url']) { + $member['click'] = 'profChangeMember(' . $profile['id'] . ',' . $member['abook_id'] . '); return false;'; $o .= micropro($member,true,'mpprof', $textmode); } } @@ -127,20 +136,17 @@ function profperm_content(&$a) { $o .= '<hr id="prof-separator" />'; $o .= '<div id="prof-all-contcts-title">'; - $o .= '<h3>' . t("All Contacts \x28with secure profile access\x29") . '</h3>'; + $o .= '<h3>' . t("All Connections") . '</h3>'; $o .= '</div>'; $o .= '<div id="prof-all-contacts">'; - - $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `blocked` = 0 and `pending` = 0 and `self` = 0 - AND `network` = 'dfrn' ORDER BY `name` ASC", - intval(local_user()) - ); - if(count($r)) { + $r = abook_connections(local_user()); + + if($r) { $textmode = (($switchtotext && (count($r) > $switchtotext)) ? true : false); foreach($r as $member) { - if(! in_array($member['id'],$ingroup)) { - $member['click'] = 'profChangeMember(' . $profile['id'] . ',' . $member['id'] . '); return true;'; + if(! in_array($member['abook_id'],$ingroup)) { + $member['click'] = 'profChangeMember(' . $profile['id'] . ',' . $member['abook_id'] . '); return false;'; $o .= micropro($member,true,'mpprof',$textmode); } } diff --git a/mod/pubsites.php b/mod/pubsites.php new file mode 100644 index 000000000..c31bbcf97 --- /dev/null +++ b/mod/pubsites.php @@ -0,0 +1,36 @@ +<?php + +function pubsites_content(&$a) { + require_once('include/dir_fns.php'); + $dirmode = intval(get_config('system','directory_mode')); + + if(($dirmode == DIRECTORY_MODE_PRIMARY) || ($dirmode == DIRECTORY_MODE_STANDALONE)) { + $url = z_root() . '/dirsearch'; + } + if(! $url) { + $directory = find_upstream_directory($dirmode); + $url = $directory['url'] . '/dirsearch'; + } + $url .= '/sites'; + + $o .= '<h1>' . t('Public Sites') . '</h1>'; + + $o .= '<div class="descriptive-text">' . + t('The listed sites allow public registration into the Red Matrix. All sites in the matrix are interlinked so membership on any of them conveys membership in the matrix as a whole. Some sites may require subscription or provide tiered service plans. The provider links <strong>may</strong> provide additional details.') . '</div>' . EOL; + + $ret = z_fetch_url($url); + if($ret['success']) { + $j = json_decode($ret['body'],true); + if($j) { + $o .= '<table border="1"><tr><td>' . t('Site URL') . '</td><td>' . t('Access Type') . '</td><td>' . t('Registration Policy') . '</td><td>' . t('Location') . '</td></tr>'; + if($j['sites']) { + foreach($j['sites'] as $jj) { + $o .= '<tr><td>' . '<a href="'. (($jj['sellpage']) ? $jj['sellpage'] : $jj['url'] . '/register' ) . '" >' . $jj['url'] . '</a>' . '</td><td>' . $jj['access'] . '</td><td>' . $jj['register'] . '</td><td>' . $jj['location'] . '</td></tr>'; + } + } + + $o .= '</table>'; + } + } + return $o; +} diff --git a/mod/qsearch.php b/mod/qsearch.php deleted file mode 100644 index c35e253b6..000000000 --- a/mod/qsearch.php +++ /dev/null @@ -1,50 +0,0 @@ -<?php - -function qsearch_init(&$a) { - - if(! local_user()) - killme(); - - $limit = (get_config('system','qsearch_limit') ? intval(get_config('system','qsearch_limit')) : 100); - - $search = ((x($_GET,'s')) ? notags(trim(urldecode($_GET['s']))) : ''); - - if(! strlen($search)) - killme(); - - - if($search) - $search = dbesc($search); - - $results = array(); - - $r = q("SELECT * FROM `group` WHERE `name` REGEXP '$search' AND `deleted` = 0 AND `uid` = %d LIMIT 0, %d ", - intval(local_user()), - intval($limit) - ); - - if(count($r)) { - - foreach($r as $rr) - $results[] = array( 0, (int) $rr['id'], $rr['name'], '', ''); - } - - $sql_extra = ((strlen($search)) ? " AND (`name` REGEXP '$search' OR `nick` REGEXP '$search') " : ""); - - - $r = q("SELECT * FROM `contact` WHERE `uid` = %d $sql_extra ORDER BY `name` ASC LIMIT 0, %d ", - intval(local_user()), - intval($limit) - ); - - - if(count($r)) { - - foreach($r as $rr) - $results[] = array( (int) $rr['id'], 0, $rr['name'],$rr['url'],$rr['photo']); - } - - echo json_encode((object) $results); - killme(); -} - diff --git a/mod/randprof.php b/mod/randprof.php index 0726b231a..bddb3251a 100644 --- a/mod/randprof.php +++ b/mod/randprof.php @@ -5,6 +5,7 @@ function randprof_init(&$a) { require_once('include/Contact.php'); $x = random_profile(); if($x) - goaway(zid($x)); + goaway(chanlink_url($x)); + // FIXME this doesn't work at the moment as a fallback goaway($a->get_baseurl() . '/profile'); } diff --git a/mod/rbmark.php b/mod/rbmark.php new file mode 100644 index 000000000..e35c2494a --- /dev/null +++ b/mod/rbmark.php @@ -0,0 +1,113 @@ +<?php /** @file */ + +require_once('acl_selectors.php'); +require_once('include/crypto.php'); +require_once('include/items.php'); +require_once('include/taxonomy.php'); +require_once('include/conversation.php'); +require_once('include/zot.php'); +require_once('include/bookmarks.php'); + +/** + * remote bookmark + * + * https://yoursite/rbmark?f=&title=&url=&private=&remote_return= + * + * This can be called via either GET or POST, use POST for long body content as suhosin often limits GET parameter length + * + * f= placeholder, often required + * title= link text + * url= URL to bookmark + * ischat=1 if this bookmark is a chatroom + * private= Don't share this link + * remote_return= absolute URL to return after posting is finished + * + */ + +function rbmark_post(&$a) { + if($_POST['submit'] !== t('Save')) + return; + + logger('rbmark_post: ' . print_r($_REQUEST,true)); + + $channel = $a->get_channel(); + + $t = array('url' => escape_tags($_REQUEST['url']),'term' => escape_tags($_REQUEST['title'])); + bookmark_add($channel,$channel,$t,((x($_REQUEST,'private')) ? intval($_REQUEST['private']) : 0), + array('menu_id' => ((x($_REQUEST,'menu_id')) ? intval($_REQUEST['menu_id']) : 0), + 'menu_name' => ((x($_REQUEST,'menu_name')) ? escape_tags($_REQUEST['menu_name']) : ''), + 'ischat' => ((x($_REQUEST['ischat'])) ? intval($_REQUEST['ischat']) : 0) + )); + + goaway(z_root() . '/bookmarks'); + +} + + +function rbmark_content(&$a) { + + $o = ''; + + if(! local_user()) { + + // The login procedure is going to bugger our $_REQUEST variables + // so save them in the session. + + if(array_key_exists('url',$_REQUEST)) { + $_SESSION['bookmark'] = $_REQUEST; + } + return login(); + } + + // If we have saved rbmark session variables, but nothing in the current $_REQUEST, recover the saved variables + + if((! array_key_exists('url',$_REQUEST)) && (array_key_exists('bookmark',$_SESSION))) { + $_REQUEST = $_SESSION['bookmark']; + unset($_SESSION['bookmark']); + } + + if($_REQUEST['remote_return']) { + $_SESSION['remote_return'] = $_REQUEST['remote_return']; + } + if(argc() > 1 && argv(1) === 'return') { + if($_SESSION['remote_return']) + goaway($_SESSION['remote_return']); + goaway(z_root() . '/bookmarks'); + } + + $channel = $a->get_channel(); + + $m = menu_list($channel,'',MENU_BOOKMARK); + $menus = array(); + if($m) { + $menus = array(0 => ''); + foreach($m as $n) { + $menus[$n['menu_id']] = $n['menu_name']; + } + } + $menu_select = array('menu_id',t('Select a bookmark folder'),false,'',$menus); + + + $o .= replace_macros(get_markup_template('rbmark.tpl'), array( + + '$header' => t('Save Bookmark'), + '$url' => array('url',t('URL of bookmark'),escape_tags($_REQUEST['url'])), + '$title' => array('title',t('Description'),escape_tags($_REQUEST['title'])), + '$ischat' => ((x($_REQUEST,'ischat')) ? intval($_REQUEST['ischat']) : 0), + '$private' => ((x($_REQUEST,'private')) ? intval($_REQUEST['private']) : 0), + '$submit' => t('Save'), + '$menu_name' => array('menu_name',t('Or enter new bookmark folder name'),'',''), + '$menus' => $menu_select + + )); + + + + + + + return $o; + +} + + diff --git a/mod/redir.php b/mod/redir.php deleted file mode 100644 index 113f6c200..000000000 --- a/mod/redir.php +++ /dev/null @@ -1,60 +0,0 @@ -<?php - -function redir_init(&$a) { - - $url = ((x($_GET,'url')) ? $_GET['url'] : ''); - - // traditional DFRN - - if(local_user() && $a->argc > 1 && intval($a->argv[1])) { - - $cid = $a->argv[1]; - - $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($cid), - intval(local_user()) - ); - - if((! count($r)) || ($r[0]['network'] !== NETWORK_DFRN)) - goaway(z_root()); - - $dfrn_id = $orig_id = (($r[0]['issued_id']) ? $r[0]['issued_id'] : $r[0]['dfrn_id']); - - if($r[0]['duplex'] && $r[0]['issued_id']) { - $orig_id = $r[0]['issued_id']; - $dfrn_id = '1:' . $orig_id; - } - if($r[0]['duplex'] && $r[0]['dfrn_id']) { - $orig_id = $r[0]['dfrn_id']; - $dfrn_id = '0:' . $orig_id; - } - - $sec = random_string(); - - q("INSERT INTO `profile_check` ( `uid`, `cid`, `dfrn_id`, `sec`, `expire`) - VALUES( %d, %s, '%s', '%s', %d )", - intval(local_user()), - intval($cid), - dbesc($dfrn_id), - dbesc($sec), - intval(time() + 45) - ); - - logger('mod_redir: ' . $r[0]['name'] . ' ' . $sec, LOGGER_DEBUG); - $dest = (($url) ? '&destination_url=' . $url : ''); - goaway ($r[0]['poll'] . '?dfrn_id=' . $dfrn_id - . '&dfrn_version=' . DFRN_PROTOCOL_VERSION . '&type=profile&sec=' . $sec . $dest ); - } - - if(local_user()) - $handle = $a->user['nickname'] . '@' . substr($a->get_baseurl(),strpos($a->get_baseurl(),'://')+3); - if(remote_user()) - $handle = $_SESSION['handle']; - - if($url) { - $url = str_replace('{zid}','&zid=' . $handle,$url); - goaway($url); - } - - goaway(z_root()); -} diff --git a/mod/register.php b/mod/register.php index dbf8d25b7..990cce2ed 100644 --- a/mod/register.php +++ b/mod/register.php @@ -7,6 +7,14 @@ function register_init(&$a) { $result = null; $cmd = ((argc() > 1) ? argv(1) : ''); + // Provide a stored request for somebody desiring a connection + // when they first need to register someplace. Once they've + // created a channel, we'll try to revive the connection request + // and process it. + + if($_REQUEST['connect']) + $_SESSION['connect'] = $_REQUEST['connect']; + switch($cmd) { case 'invite_check.json': $result = check_account_invite($_REQUEST['invite_code']); @@ -30,7 +38,7 @@ function register_post(&$a) { $max_dailies = intval(get_config('system','max_daily_registrations')); if($max_dailies) { - $r = q("select count(*) as total from account where account_created > UTC_TIMESTAMP - INTERVAL 1 day"); + $r = q("select count(account_id) as total from account where account_created > UTC_TIMESTAMP() - INTERVAL 1 day"); if($r && $r[0]['total'] >= $max_dailies) { notice( t('Maximum daily site registrations exceeded. Please try again tomorrow.') . EOL); return; @@ -51,7 +59,7 @@ function register_post(&$a) { break; case REGISTER_APPROVE: - $flags = ACCOUNT_UNVERIFIED | ACCOUNT_BLOCKED; + $flags = ACCOUNT_UNVERIFIED | ACCOUNT_BLOCKED | ACCOUNT_PENDING; break; default: @@ -64,6 +72,12 @@ function register_post(&$a) { break; } + + if((! $_POST['password']) || ($_POST['password'] !== $_POST['password2'])) { + notice( t('Passwords do not match.') . EOL); + return; + } + $arr = $_POST; $arr['account_flags'] = $flags; @@ -121,15 +135,22 @@ function register_post(&$a) { function register_content(&$a) { + $registration_is = ''; + $other_sites = ''; if(get_config('system','register_policy') == REGISTER_CLOSED) { - notice("Permission denied." . EOL); - return; + require_once('mod/pubsites.php'); + return pubsites_content($a); + } + + if(get_config('system','register_policy') == REGISTER_APPROVE) { + $registration_is = t('Registration on this site/hub is by approval only.'); + $other_sites = t('<a href="pubsites">Register at another affiliated site/hub</a>'); } $max_dailies = intval(get_config('system','max_daily_registrations')); if($max_dailies) { - $r = q("select count(*) as total from account where account_created > UTC_TIMESTAMP - INTERVAL 1 day"); + $r = q("select count(account_id) as total from account where account_created > UTC_TIMESTAMP() - INTERVAL 1 day"); if($r && $r[0]['total'] >= $max_dailies) { logger('max daily registrations exceeded.'); notice( t('This site has exceeded the number of allowed daily account registrations. Please try again tomorrow.') . EOL); @@ -161,10 +182,14 @@ function register_content(&$a) { $invite_code = ((x($_REQUEST,'invite_code')) ? strip_tags(trim($_REQUEST['invite_code'])) : "" ); + + $o = replace_macros(get_markup_template('register.tpl'), array( '$title' => t('Registration'), + '$reg_is' => $registration_is, '$registertext' => get_config('system','register_text'), + '$other_sites' => $other_sites, '$invitations' => get_config('system','invitation_only'), '$invite_desc' => t('Membership on this site is by invitation only.'), '$label_invite' => t('Please enter your invitation code'), diff --git a/mod/regmod.php b/mod/regmod.php index 3da1575d3..c54c0d88e 100644 --- a/mod/regmod.php +++ b/mod/regmod.php @@ -1,104 +1,6 @@ <?php -function user_allow($hash) { - - $a = get_app(); - - $register = q("SELECT * FROM `register` WHERE `hash` = '%s' LIMIT 1", - dbesc($hash) - ); - - - if(! count($register)) - return false; - - $user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", - intval($register[0]['uid']) - ); - - if(! count($user)) - killme(); - - $r = q("DELETE FROM `register` WHERE `hash` = '%s' LIMIT 1", - dbesc($register[0]['hash']) - ); - - - $r = q("UPDATE `user` SET `blocked` = 0, `verified` = 1 WHERE `uid` = %d LIMIT 1", - intval($register[0]['uid']) - ); - - $r = q("SELECT * FROM `profile` WHERE `uid` = %d AND `is_default` = 1", - intval($user[0]['uid']) - ); - if(count($r) && $r[0]['publish']) { - $url = $a->get_baseurl() . '/profile/' . $user[0]['nickname']; - if($url && strlen(get_config('system','directory_submit_url'))) - proc_run('php',"include/directory.php","$url"); - } - - push_lang($register[0]['language']); - - $email_tpl = get_intltext_template("register_open_eml.tpl"); - $email_tpl = replace_macros($email_tpl, array( - '$sitename' => $a->config['sitename'], - '$siteurl' => $a->get_baseurl(), - '$username' => $user[0]['username'], - '$email' => $user[0]['email'], - '$password' => $register[0]['password'], - '$uid' => $user[0]['uid'] - )); - - $res = mail($user[0]['email'], sprintf(t('Registration details for %s'), $a->config['sitename']), - $email_tpl, - 'From: ' . t('Administrator') . '@' . $_SERVER['SERVER_NAME'] . "\n" - . 'Content-type: text/plain; charset=UTF-8' . "\n" - . 'Content-transfer-encoding: 8bit' ); - - pop_lang(); - - if($res) { - info( t('Account approved.') . EOL ); - return true; - } - -} - - -// This does not have to go through user_remove() and save the nickname -// permanently against re-registration, as the person was not yet -// allowed to have friends on this system - -function user_deny($hash) { - - $register = q("SELECT * FROM `register` WHERE `hash` = '%s' LIMIT 1", - dbesc($hash) - ); - - if(! count($register)) - return false; - - $user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", - intval($register[0]['uid']) - ); - - $r = q("DELETE FROM `user` WHERE `uid` = %d LIMIT 1", - intval($register[0]['uid']) - ); - $r = q("DELETE FROM `contact` WHERE `uid` = %d LIMIT 1", - intval($register[0]['uid']) - ); - $r = q("DELETE FROM `profile` WHERE `uid` = %d LIMIT 1", - intval($register[0]['uid']) - ); - - $r = q("DELETE FROM `register` WHERE `hash` = '%s' LIMIT 1", - dbesc($register[0]['hash']) - ); - notice( sprintf(t('Registration revoked for %s'), $user[0]['username']) . EOL); - return true; - -} +require_once('include/account.php'); function regmod_content(&$a) { @@ -117,13 +19,11 @@ function regmod_content(&$a) { return ''; } - if($a->argc != 3) + if(argc() != 3) killme(); - $cmd = $a->argv[1]; - $hash = $a->argv[2]; - - + $cmd = argv(1); + $hash = argv(2); if($cmd === 'deny') { if (!user_deny($hash)) killme(); diff --git a/mod/removeme.php b/mod/removeme.php index ee88bd76a..f0b4ae3c0 100644 --- a/mod/removeme.php +++ b/mod/removeme.php @@ -17,13 +17,17 @@ function removeme_post(&$a) { if($_POST['verify'] !== $_SESSION['remove_account_verify']) return; - $encrypted = hash('whirlpool',trim($_POST['qxz_password'])); - if((strlen($a->user['password'])) && ($encrypted === $a->user['password'])) { - require_once('include/Contact.php'); - user_remove($a->user['uid']); - // NOTREACHED - } + $account = $a->get_account(); + + if(! account_verify_password($account['account_email'],$_POST['qxz_password'])) + return; + + require_once('include/Contact.php'); + + $global_remove = intval($_POST['global']); + + channel_remove(local_user(),1 - $global_remove); } @@ -42,10 +46,11 @@ function removeme_content(&$a) { $o .= replace_macros($tpl, array( '$basedir' => $a->get_baseurl(), '$hash' => $hash, - '$title' => t('Remove My Account'), - '$desc' => t('This will completely remove your account. Once this has been done it is not recoverable.'), + '$title' => t('Remove This Channel'), + '$desc' => t('This will completely remove this channel from the network. Once this has been done it is not recoverable.'), '$passwd' => t('Please enter your password for verification:'), - '$submit' => t('Remove My Account') + '$global' => array('global', t('Remove this channel and all its clones from the network'), false, t('By default only the instance of the channel located on this hub will be removed from the network')), + '$submit' => t('Remove Channel') )); return $o; diff --git a/mod/rmagic.php b/mod/rmagic.php new file mode 100644 index 000000000..946277327 --- /dev/null +++ b/mod/rmagic.php @@ -0,0 +1,84 @@ +<?php + + +function rmagic_init(&$a) { + + if(local_user()) + goaway(z_root()); + + $me = get_my_address(); + if($me) { + $r = q("select hubloc_url from hubloc where hubloc_addr = '%s' limit 1", + dbesc($me) + ); + if($r) { + if($r[0]['hubloc_url'] === z_root()) + goaway(z_root() . '/login'); + $dest = z_root() . '/' . str_replace('zid=','zid_=',get_app()->query_string); + goaway($r[0]['hubloc_url'] . '/magic' . '?f=&dest=' . $dest); + } + } +} + +function rmagic_post(&$a) { + + $address = trim($_REQUEST['address']); + + if(strpos($address,'@') === false) { + $arr = array('address' => $address); + call_hooks('reverse_magic_auth', $arr); + + try { + require_once('library/openid/openid.php'); + $openid = new LightOpenID(z_root()); + $openid->identity = $address; + $openid->returnUrl = z_root() . '/openid'; + goaway($openid->authUrl()); + } catch (Exception $e) { + notice( t('We encountered a problem while logging in with the OpenID you provided. Please check the correct spelling of the ID.').'<br /><br >'. t('The error message was:').' '.$e->getMessage()); + } + + // if they're still here... + notice( t('Authentication failed.') . EOL); + return; + } + else { + + // Presumed Red identity. Perform reverse magic auth + + if(strpos($address,'@') === false) { + notice('Invalid address.'); + return; + } + + $r = null; + if($address) { + $r = q("select hubloc_url from hubloc where hubloc_addr = '%s' limit 1", + dbesc($address) + ); + } + if($r) { + $url = $r[0]['hubloc_url']; + } + else { + $url = 'https://' . substr($address,strpos($address,'@')+1); + } + + if($url) { + $dest = z_root() . '/' . str_replace('zid=','zid_=',$a->query_string); + goaway($url . '/magic' . '?f=&dest=' . $dest); + } + } +} + + +function rmagic_content(&$a) { + + $o = replace_macros(get_markup_template('rmagic.tpl'),array( + '$title' => t('Remote Authentication'), + '$desc' => t('Enter your channel address (e.g. channel@example.com)'), + '$submit' => t('Authenticate') + )); + return $o; + +}
\ No newline at end of file diff --git a/mod/rpost.php b/mod/rpost.php new file mode 100644 index 000000000..309208870 --- /dev/null +++ b/mod/rpost.php @@ -0,0 +1,136 @@ +<?php /** @file */ + +require_once('acl_selectors.php'); +require_once('include/crypto.php'); +require_once('include/items.php'); +require_once('include/taxonomy.php'); +require_once('include/conversation.php'); +require_once('include/zot.php'); + +/** + * remote post + * + * https://yoursite/rpost?f=&title=&body=&remote_return= + * + * This can be called via either GET or POST, use POST for long body content as suhosin often limits GET parameter length + * + * f= placeholder, often required + * title= Title of post + * body= Body of post + * source= Source application + * remote_return= absolute URL to return after posting is finished + * type= choices are 'html' or 'bbcode', default is 'bbcode' + * + */ + + + +function rpost_content(&$a) { + + $o = ''; + + if(! local_user()) { + if(remote_user()) { + // redirect to your own site. + // We can only do this with a GET request so you'll need to keep the text short or risk getting truncated + // by the wretched beast called 'suhosin'. All the browsers now allow long GET requests, but suhosin + // blocks them. + + $url = get_rpost_path($a->get_observer()); + // make sure we're not looping to our own hub + if(($url) && (! stristr($url, $a->get_hostname()))) { + foreach($_REQUEST as $key => $arg) { + $url .= '&' . $key . '=' . $arg; + } + goaway($url); + } + } + + // The login procedure is going to bugger our $_REQUEST variables + // so save them in the session. + + if(array_key_exists('body',$_REQUEST)) { + $_SESSION['rpost'] = $_REQUEST; + } + return login(); + } + + // If we have saved rpost session variables, but nothing in the current $_REQUEST, recover the saved variables + + if((! array_key_exists('body',$_REQUEST)) && (array_key_exists('rpost',$_SESSION))) { + $_REQUEST = $_SESSION['rpost']; + unset($_SESSION['rpost']); + } + + if(array_key_exists('channel',$_REQUEST)) { + $r = q("select channel_id from channel where channel_account_id = %d and channel_address = '%s' limit 1", + intval(get_account_id()), + dbesc($_REQUEST['channel']) + ); + if($r) { + require_once('include/security.php'); + $change = change_channel($r[0]['channel_id']); + } + } + + if($_REQUEST['remote_return']) { + $_SESSION['remote_return'] = $_REQUEST['remote_return']; + } + if(argc() > 1 && argv(1) === 'return') { + if($_SESSION['remote_return']) + goaway($_SESSION['remote_return']); + goaway(z_root() . '/network'); + } + + $plaintext = true; + if(feature_enabled(local_user(),'richtext')) + $plaintext = false; + + if(array_key_exists('type', $_REQUEST) && $_REQUEST['type'] === 'html') { + require_once('include/html2bbcode.php'); + $_REQUEST['body'] = html2bbcode($_REQUEST['body']); + } + + $channel = $a->get_channel(); + + $o .= replace_macros(get_markup_template('edpost_head.tpl'), array( + '$title' => t('Edit post') + )); + + +// $a->page['htmlhead'] .= replace_macros(get_markup_template('jot-header.tpl'), array( +// '$baseurl' => $a->get_baseurl(), +// '$editselect' => (($plaintext) ? 'none' : '/(profile-jot-text|prvmail-text)/'), +// '$ispublic' => ' ', // t('Visible to <strong>everybody</strong>'), +// '$geotag' => $geotag, +// '$nickname' => $channel['channel_address'] +// )); + + + + $x = array( + 'is_owner' => true, + 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''), + 'default_location' => $channel['channel_location'], + 'nickname' => $channel['channel_address'], + 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] + || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), + 'acl' => populate_acl($channel, $false), + 'bang' => '', +// 'channel_select' => true, + 'visitor' => true, + 'profile_uid' => local_user(), + 'title' => $_REQUEST['title'], + 'body' => $_REQUEST['body'], + 'source' => ((x($_REQUEST,'source')) ? strip_tags($_REQUEST['source']) : ''), + 'return_path' => 'rpost/return' + ); + + + $o .= status_editor($a,$x); + + return $o; + +} + + diff --git a/mod/search.php b/mod/search.php index 6f40ad4b0..663d355e2 100644 --- a/mod/search.php +++ b/mod/search.php @@ -1,86 +1,19 @@ <?php -function search_saved_searches() { - - if(! feature_enabled(local_user(),'savedsearch')) - return ''; - - $o = ''; - - $r = q("select `tid`,`term` from `term` WHERE `uid` = %d and type = %d", - intval(local_user()), - intval(TERM_SAVEDSEARCH) - ); - - if(count($r)) { - $o .= '<div id="saved-search-list" class="widget">'; - $o .= '<h3>' . t('Saved Searches') . '</h3>' . "\r\n"; - $o .= '<ul id="saved-search-ul">' . "\r\n"; - foreach($r as $rr) { - $o .= '<li class="saved-search-li clear"><a href="search/?f=&remove=1&search=' . $rr['term'] . '" class="icon drophide savedsearchdrop" title="' . t('Remove term') . '" onclick="return confirmDelete();" onmouseover="imgbright(this);" onmouseout="imgdull(this);" ></a> <a href="search/?f=&search=' . $rr['term'] . '" class="savedsearchterm" >' . htmlspecialchars($rr['term']) . '</a></li>' . "\r\n"; - } - $o .= '</ul><div class="clear"></div></div>' . "\r\n"; - } - - return $o; - -} - - function search_init(&$a) { - - $search = ((x($_GET,'search')) ? trim(rawurldecode($_GET['search'])) : ''); - - if(local_user()) { - if(x($_GET,'save') && $search) { - $r = q("select `tid` from `term` where `uid` = %d and `type` = %d and `term` = '%s' limit 1", - intval(local_user()), - intval(TERM_SAVEDSEARCH), - dbesc($search) - ); - if(! count($r)) { - q("insert into `term` ( `uid`,`type`,`term` ) values ( %d, %d, '%s') ", - intval(local_user()), - intval(TERM_SAVEDSEARCH), - dbesc($search) - ); - } - } - if(x($_GET,'remove') && $search) { - q("delete from `term` where `uid` = %d and `type` = %d and `term` = '%s' limit 1", - intval(local_user()), - intval(TERM_SAVEDSEARCH), - dbesc($search) - ); - } - - $a->page['aside'] .= search_saved_searches(); - - } - else { - unset($_SESSION['theme']); - unset($_SESSION['mobile-theme']); - } - - - -} - - - -function search_post(&$a) { - if(x($_POST,'search')) - $a->data['search'] = $_POST['search']; + if(x($_REQUEST,'search')) + $a->data['search'] = $_REQUEST['search']; } -function search_content(&$a) { +function search_content(&$a,$update = 0, $load = false) { - if((get_config('system','block_public')) && (! local_user()) && (! remote_user())) { - notice( t('Public access denied.') . EOL); + if((get_config('system','block_public')) || (get_config('system','block_public_search'))) { + if ((! local_user()) && (! remote_user())) { + notice( t('Public access denied.') . EOL); return; + } } - nav_set_selected('search'); require_once("include/bbcode.php"); @@ -106,15 +39,21 @@ function search_content(&$a) { $search = ((x($_GET,'tag')) ? trim(rawurldecode($_GET['tag'])) : ''); } - $o .= search($search,'search-box','/search',((local_user()) ? true : false)); + if((! local_user()) || (! feature_enabled(local_user(),'savedsearch'))) + $o .= search($search,'search-box','/search',((local_user()) ? true : false)); if(strpos($search,'#') === 0) { $tag = true; $search = substr($search,1); } if(strpos($search,'@') === 0) { - require_once('mod/dirfind.php'); - return dirfind_content($a); + $search = substr($search,1); + goaway(z_root() . '/directory' . '?f=1&search=' . $search); + } + + // look for a naked webbie + if(strpos($search,'@') !== false) { + goaway(z_root() . '/directory' . '?f=1&search=' . $search); } if(! $search) @@ -128,10 +67,7 @@ function search_content(&$a) { ); } else { - if (get_config('system','use_fulltext_engine')) - $sql_extra = sprintf(" AND MATCH (`item`.`body`) AGAINST ('".'"%s"'."' in boolean mode) ", dbesc(protect_sprintf($search))); - else - $sql_extra = sprintf(" AND `item`.`body` REGEXP '%s' ", dbesc(protect_sprintf(preg_quote($search)))); + $sql_extra = sprintf(" AND `item`.`body` REGEXP '%s' ", dbesc(protect_sprintf(preg_quote($search)))); } // Here is the way permissions work in the search module... @@ -139,16 +75,13 @@ function search_content(&$a) { // OR your own posts if you are a logged in member // No items will be shown if the member has a blocked profile wall. - - - if((! $update) && (! $load)) { // This is ugly, but we can't pass the profile_uid through the session to the ajax updater, // because browser prefetching might change it on us. We have to deliver it with the page. - $o .= '<div id="live-channel"></div>' . "\r\n"; - $o .= "<script> var profile_uid = " . $a->profile['profile_uid'] + $o .= '<div id="live-search"></div>' . "\r\n"; + $o .= "<script> var profile_uid = " . ((intval(local_user())) ? local_user() : (-1)) . "; var netargs = '?f='; var profile_page = " . $a->pager['page'] . "; </script>\r\n"; $a->page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array( @@ -163,13 +96,16 @@ function search_content(&$a) { '$liked' => '0', '$conv' => '0', '$spam' => '0', + '$fh' => '0', '$nouveau' => '0', '$wall' => '0', + '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), '$page' => (($a->pager['page'] != 1) ? $a->pager['page'] : 1), - '$search' => (($tag) ? '#' : '') . $search, + '$search' => (($tag) ? urlencode('#') : '') . $search, '$order' => '', '$file' => '', '$cats' => '', + '$mid' => '', '$dend' => '', '$dbegin' => '' )); @@ -177,24 +113,43 @@ function search_content(&$a) { } + $pub_sql = public_permissions_sql(get_observer_hash()); + require_once('include/identity.php'); - if(($update) && ($load)) { + $sys = get_sys_channel(); + if(($update) && ($load)) { + $itemspage = get_pconfig(local_user(),'system','itemspage'); + $a->set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); $pager_sql = sprintf(" LIMIT %d, %d ",intval($a->pager['start']), intval($a->pager['itemspage'])); if($load) { - $r = q("SELECT distinct(uri), item.* from item - WHERE item_restrict = 0 - AND (( `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = '' AND not ( item_flags & %d )) - OR ( `item`.`uid` = %d )) - $sql_extra - group by uri ORDER BY created DESC $pager_sql ", - intval(ITEM_PRIVATE), - intval(local_user()), - intval(ABOOK_FLAG_BLOCKED) - - ); + $r = null; + + if(local_user()) { + $r = q("SELECT distinct mid, item.id as item_id, item.* from item + WHERE item_restrict = 0 + AND ((( `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = '' AND item_private = 0 ) + OR ( `item`.`uid` = %d )) OR item.owner_xchan = '%s' ) + $sql_extra + group by mid ORDER BY created DESC $pager_sql ", + intval(local_user()), + dbesc($sys['xchan_hash']) + ); + } + if($r === null) { + $r = q("SELECT distinct mid, item.id as item_id, item.* from item + WHERE item_restrict = 0 + AND (((( `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' + AND `item`.`deny_gid` = '' AND item_private = 0 ) + and owner_xchan in ( " . stream_perms_xchans(($observer) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " )) + $pub_sql ) OR owner_xchan = '%s') + $sql_extra + group by mid ORDER BY created DESC $pager_sql", + dbesc($sys['xchan_hash']) + ); + } } else { $r = array(); @@ -202,64 +157,18 @@ function search_content(&$a) { } if($r) { - - $parents_str = ids_to_querystr($r,'item_id'); - - $items = q("SELECT `item`.*, `item`.`id` AS `item_id` - FROM `item` - WHERE item_restrict = 0 and - $sql_extra ", - intval($a->profile['profile_uid']), - dbesc($parents_str) - ); - - xchan_query($items); - $items = fetch_post_tags($items); - $items = conv_sort($items,'created'); - + xchan_query($r); + $items = fetch_post_tags($r,true); } else { $items = array(); } - - - $r = q("SELECT distinct(`item`.`uri`), `item`.*, `item`.`id` AS `item_id`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`alias`, `contact`.`rel`, - `contact`.`network`, `contact`.`thumb`, `contact`.`self`, `contact`.`writable`, - `contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid`, - `user`.`nickname` - FROM `item` LEFT JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - LEFT JOIN `user` ON `user`.`uid` = `item`.`uid` - WHERE `item`.`visible` = 1 AND `item`.`deleted` = 0 and `item`.`moderated` = 0 - AND (( `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = '' AND `item`.`private` = 0 AND `user`.`hidewall` = 0 ) - OR `item`.`uid` = %d ) - AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0 - $sql_extra - group by `item`.`uri` - ORDER BY `received` DESC LIMIT %d , %d ", - intval(local_user()), - intval($a->pager['start']), - intval($a->pager['itemspage']) - - ); - - -// $a = fetch_post_tags($a); - - if(! count($r)) { - info( t('No results.') . EOL); - return $o; - } - - if($tag) - $o .= '<h2>Items tagged with: ' . htmlspecialchars($search) . '</h2>'; + $o .= '<h2>Items tagged with: ' . htmlspecialchars($search, ENT_COMPAT,'UTF-8') . '</h2>'; else - $o .= '<h2>Search results for: ' . htmlspecialchars($search) . '</h2>'; - - $o .= conversation($a,$r,'search',false); + $o .= '<h2>Search results for: ' . htmlspecialchars($search, ENT_COMPAT,'UTF-8') . '</h2>'; - $o .= alt_pager($a,count($r)); + $o .= conversation($a,$items,'search',$update,'client'); return $o; } diff --git a/mod/search_ac.php b/mod/search_ac.php index 5bc3c1c0b..36da21376 100644 --- a/mod/search_ac.php +++ b/mod/search_ac.php @@ -27,43 +27,27 @@ function search_ac_init(&$a){ // Priority to people searches if ($search) { - $people_sql_extra = protect_sprintf(" AND `name` LIKE '%". dbesc($search) . "%' "); + $people_sql_extra = protect_sprintf(" AND `xchan_name` LIKE '%". dbesc($search) . "%' "); $tag_sql_extra = protect_sprintf(" AND term LIKE '%". dbesc($search) . "%' "); } - $r = q("SELECT `id`, `name`, `micro`, `url` FROM `contact` - WHERE `uid` = %d AND `pending` = 0 + + $r = q("SELECT `abook_id`, `xchan_name`, `xchan_photo_s`, `xchan_url` FROM `abook` left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d $people_sql_extra - ORDER BY `name` ASC ", + ORDER BY `xchan_name` ASC ", intval(local_user()) ); - if(count($r)) { + if($r) { foreach($r as $g) { - $x['photos'][] = $g['micro']; - $x['links'][] = $g['url']; - $x['suggestions'][] = '@' . $g['name']; - $x['data'][] = intval($g['id']); - } - } - else { - - $r = q("SELECT `id`, `name`, `photo`, `url` FROM `gcontact` where 1 - $people_sql_extra - ORDER BY `name` ASC " - ); - - if(count($r)) { - foreach($r as $g) { - $x['photos'][] = $g['photo']; - $x['links'][] = $g['url']; - $x['suggestions'][] = '@' . $g['name']; - $x['data'][] = intval($g['id']); - } + $x['photos'][] = $g['xchan_photo_s']; + $x['links'][] = $g['xchan_url']; + $x['suggestions'][] = '@' . $g['xchan_name']; + $x['data'][] = 'cid=' . intval($g['abook_id']); } } - $r = q("select tid, term, url from term where type = %d $tag_sql_extra order by term asc", + $r = q("select distinct term, tid, url from term where type = %d $tag_sql_extra group by term order by term asc", intval(TERM_HASHTAG) ); diff --git a/mod/settings.php b/mod/settings.php index db204bc50..c72fdc8c4 100644 --- a/mod/settings.php +++ b/mod/settings.php @@ -1,5 +1,6 @@ -<?php +<?php /** @file */ +require_once('include/zot.php'); function get_theme_config_file($theme){ @@ -15,67 +16,20 @@ function get_theme_config_file($theme){ } function settings_init(&$a) { + if(! local_user()) + return; + $a->profile_uid = local_user(); // default is channel settings in the absence of other arguments if(argc() == 1) { + // We are setting these values - don't use the argc(), argv() functions here $a->argc = 2; $a->argv[] = 'channel'; } - $tabs = array( - array( - 'label' => t('Account settings'), - 'url' => $a->get_baseurl(true).'/settings/account', - 'selected' => ((argv(1) === 'account') ? 'active' : ''), - ), - - array( - 'label' => t('Channel settings'), - 'url' => $a->get_baseurl(true).'/settings/channel', - 'selected' => ((argv(1) === 'channel') ? 'active' : ''), - ), - - array( - 'label' => t('Additional features'), - 'url' => $a->get_baseurl(true).'/settings/features', - 'selected' => ((argv(1) === 'features') ? 'active' : ''), - ), - - array( - 'label' => t('Feature settings'), - 'url' => $a->get_baseurl(true).'/settings/featured', - 'selected' => ((argv(1) === 'addon') ? 'active' : ''), - ), - - array( - 'label' => t('Display settings'), - 'url' => $a->get_baseurl(true).'/settings/display', - 'selected' => ((argv(1) === 'display') ? 'active' : ''), - ), - - array( - 'label' => t('Connected apps'), - 'url' => $a->get_baseurl(true) . '/settings/oauth', - 'selected' => ((argv(1) === 'oauth') ? 'active' : ''), - ), - - array( - 'label' => t('Export personal data'), - 'url' => $a->get_baseurl(true) . '/uexport', - 'selected' => '' - ), - - ); - - $tabtpl = get_markup_template("generic_links_widget.tpl"); - $a->page['aside'] = replace_macros($tabtpl, array( - '$title' => t('Settings'), - '$class' => 'settings-widget', - '$items' => $tabs, - )); } @@ -85,16 +39,11 @@ function settings_post(&$a) { if(! local_user()) return; - if(x($_SESSION,'submanage') && intval($_SESSION['submanage'])) - return; - + // logger('mod_settings: ' . print_r($_REQUEST,true)); - if(count($a->user) && x($a->user,'uid') && $a->user['uid'] != local_user()) { - notice( t('Permission denied.') . EOL); + if(x($_SESSION,'submanage') && intval($_SESSION['submanage'])) return; - } - $old_page_flags = $a->user['page-flags']; if((argc() > 1) && (argv(1) === 'oauth') && x($_POST,'remove')){ check_form_security_token_redirectOnErr('/settings/oauth', 'settings_oauth'); @@ -116,10 +65,17 @@ function settings_post(&$a) { $secret = ((x($_POST,'secret')) ? $_POST['secret'] : ''); $redirect = ((x($_POST,'redirect')) ? $_POST['redirect'] : ''); $icon = ((x($_POST,'icon')) ? $_POST['icon'] : ''); - if ($name=="" || $key=="" || $secret==""){ - notice(t("Missing some important data!")); - - } else { + $ok = true; + if($name == '') { + $ok = false; + notice( t('Name is required') . EOL); + } + if($key == '' || $secret == '') { + $ok = false; + notice( t('Key and Secret are required') . EOL); + } + + if($ok) { if ($_POST['submit']==t("Update")){ $r = q("UPDATE clients SET client_id='%s', @@ -155,11 +111,8 @@ function settings_post(&$a) { if((argc() > 1) && (argv(1) == 'featured')) { check_form_security_token_redirectOnErr('/settings/featured', 'settings_featured'); - - - - - call_hooks('featured_settings_post', $_POST); + call_hooks('feature_settings_post', $_POST); + build_sync_packet(); return; } @@ -172,6 +125,7 @@ function settings_post(&$a) { set_pconfig(local_user(),'feature',substr($k,8),((intval($v)) ? 1 : 0)); } } + build_sync_packet(); return; } @@ -187,7 +141,7 @@ function settings_post(&$a) { if($browser_update < 10000) $browser_update = 10000; - $itemspage = ((x($_POST,'itemspage')) ? intval($_POST['itemspage']) : 40); + $itemspage = ((x($_POST,'itemspage')) ? intval($_POST['itemspage']) : 20); if($itemspage > 100) $itemspage = 100; @@ -196,9 +150,12 @@ function settings_post(&$a) { set_pconfig(local_user(),'system','mobile_theme',$mobile_theme); } +// $chanview_full = ((x($_POST,'chanview_full')) ? intval($_POST['chanview_full']) : 0); + set_pconfig(local_user(),'system','update_interval', $browser_update); set_pconfig(local_user(),'system','itemspage', $itemspage); set_pconfig(local_user(),'system','no_smilies',$nosmile); +// set_pconfig(local_user(),'system','chanview_full',$chanview_full); if ($theme == $a->channel['channel_theme']){ @@ -215,6 +172,7 @@ function settings_post(&$a) { ); call_hooks('display_settings_post', $_POST); + build_sync_packet(); goaway($a->get_baseurl(true) . '/settings/display' ); return; // NOTREACHED } @@ -264,13 +222,13 @@ function settings_post(&$a) { } $email = ((x($_POST,'email')) ? trim(notags($_POST['email'])) : ''); + $account = $a->get_account(); if($email != $account['account_email']) { - $account = $a->get_account(); if(! valid_email($email)) $errs[] = t('Not valid email.'); $adm = trim(get_config('system','admin_email')); if(($adm) && (strcasecmp($email,$adm) == 0)) { - $errs[] = t('Protected email. Cannot change to that email.'); + $errs[] = t('Protected email address. Cannot change to that email.'); $email = $a->user['email']; } if(! $errs) { @@ -302,19 +260,18 @@ function settings_post(&$a) { $openid = ((x($_POST,'openid_url')) ? notags(trim($_POST['openid_url'])) : ''); $maxreq = ((x($_POST,'maxreq')) ? intval($_POST['maxreq']) : 0); $expire = ((x($_POST,'expire')) ? intval($_POST['expire']) : 0); - $def_gid = ((x($_POST,'group-selection')) ? intval($_POST['group-selection']) : 0); - + $def_group = ((x($_POST,'group-selection')) ? notags(trim($_POST['group-selection'])) : ''); + $channel_menu = ((x($_POST['channel_menu'])) ? htmlspecialchars_decode(trim($_POST['channel_menu']),ENT_QUOTES) : ''); $expire_items = ((x($_POST,'expire_items')) ? intval($_POST['expire_items']) : 0); - $expire_notes = ((x($_POST,'expire_notes')) ? intval($_POST['expire_notes']) : 0); $expire_starred = ((x($_POST,'expire_starred')) ? intval($_POST['expire_starred']) : 0); $expire_photos = ((x($_POST,'expire_photos'))? intval($_POST['expire_photos']) : 0); $expire_network_only = ((x($_POST,'expire_network_only'))? intval($_POST['expire_network_only']) : 0); $allow_location = (((x($_POST,'allow_location')) && (intval($_POST['allow_location']) == 1)) ? 1: 0); + $hide_presence = (((x($_POST,'hide_presence')) && (intval($_POST['hide_presence']) == 1)) ? 1: 0); + $publish = (((x($_POST,'profile_in_directory')) && (intval($_POST['profile_in_directory']) == 1)) ? 1: 0); - $net_publish = (((x($_POST,'profile_in_netdirectory')) && (intval($_POST['profile_in_netdirectory']) == 1)) ? 1: 0); - $old_visibility = (((x($_POST,'visibility')) && (intval($_POST['visibility']) == 1)) ? 1 : 0); $page_flags = (((x($_POST,'page-flags')) && (intval($_POST['page-flags']))) ? intval($_POST['page-flags']) : 0); $blockwall = (((x($_POST,'blockwall')) && (intval($_POST['blockwall']) == 1)) ? 0: 1); // this setting is inverted! $blocktags = (((x($_POST,'blocktags')) && (intval($_POST['blocktags']) == 1)) ? 0: 1); // this setting is inverted! @@ -326,24 +283,34 @@ function settings_post(&$a) { $post_newfriend = (($_POST['post_newfriend'] == 1) ? 1: 0); $post_joingroup = (($_POST['post_joingroup'] == 1) ? 1: 0); $post_profilechange = (($_POST['post_profilechange'] == 1) ? 1: 0); + $adult = (($_POST['adult'] == 1) ? 1 : 0); - $arr = array(); - $arr['channel_r_stream'] = (($_POST['view_stream']) ? $_POST['view_stream'] : 0); - $arr['channel_r_profile'] = (($_POST['view_profile']) ? $_POST['view_profile'] : 0); - $arr['channel_r_photos'] = (($_POST['view_photos']) ? $_POST['view_photos'] : 0); - $arr['channel_r_abook'] = (($_POST['view_contacts']) ? $_POST['view_contacts'] : 0); - $arr['channel_w_stream'] = (($_POST['send_stream']) ? $_POST['send_stream'] : 0); - $arr['channel_w_wall'] = (($_POST['post_wall']) ? $_POST['post_wall'] : 0); - $arr['channel_w_tagwall'] = (($_POST['tag_deliver']) ? $_POST['tag_deliver'] : 0); - $arr['channel_w_comment'] = (($_POST['post_comments']) ? $_POST['post_comments'] : 0); - $arr['channel_w_mail'] = (($_POST['post_mail']) ? $_POST['post_mail'] : 0); - $arr['channel_w_photos'] = (($_POST['post_photos']) ? $_POST['post_photos'] : 0); - $arr['channel_w_chat'] = (($_POST['chat']) ? $_POST['chat'] : 0); - $arr['channel_a_delegate'] = (($_POST['delegate']) ? $_POST['delegate'] : 0); - $arr['channel_r_storage'] = (($_POST['view_storage']) ? $_POST['view_storage'] : 0); - $arr['channel_w_storage'] = (($_POST['write_storage']) ? $_POST['write_storage'] : 0); - + $channel = $a->get_channel(); + $pageflags = $channel['channel_pageflags']; + $existing_adult = (($pageflags & PAGE_ADULT) ? 1 : 0); + if($adult != $existing_adult) + $pageflags = ($pageflags ^ PAGE_ADULT); + $arr = array(); + $arr['channel_r_stream'] = (($_POST['view_stream']) ? $_POST['view_stream'] : 0); + $arr['channel_r_profile'] = (($_POST['view_profile']) ? $_POST['view_profile'] : 0); + $arr['channel_r_photos'] = (($_POST['view_photos']) ? $_POST['view_photos'] : 0); + $arr['channel_r_abook'] = (($_POST['view_contacts']) ? $_POST['view_contacts'] : 0); + $arr['channel_w_stream'] = (($_POST['send_stream']) ? $_POST['send_stream'] : 0); + $arr['channel_w_wall'] = (($_POST['post_wall']) ? $_POST['post_wall'] : 0); + $arr['channel_w_tagwall'] = (($_POST['tag_deliver']) ? $_POST['tag_deliver'] : 0); + $arr['channel_w_comment'] = (($_POST['post_comments']) ? $_POST['post_comments'] : 0); + $arr['channel_w_mail'] = (($_POST['post_mail']) ? $_POST['post_mail'] : 0); + $arr['channel_w_photos'] = (($_POST['post_photos']) ? $_POST['post_photos'] : 0); + $arr['channel_w_chat'] = (($_POST['chat']) ? $_POST['chat'] : 0); + $arr['channel_a_delegate'] = (($_POST['delegate']) ? $_POST['delegate'] : 0); + $arr['channel_r_storage'] = (($_POST['view_storage']) ? $_POST['view_storage'] : 0); + $arr['channel_w_storage'] = (($_POST['write_storage']) ? $_POST['write_storage'] : 0); + $arr['channel_r_pages'] = (($_POST['view_pages']) ? $_POST['view_pages'] : 0); + $arr['channel_w_pages'] = (($_POST['write_pages']) ? $_POST['write_pages'] : 0); + $arr['channel_a_republish'] = (($_POST['republish']) ? $_POST['republish'] : 0); + $arr['channel_a_bookmark'] = (($_POST['bookmark']) ? $_POST['bookmark'] : 0); + $defperms = 0; if(x($_POST['def_view_stream'])) $defperms += $_POST['def_view_stream']; @@ -373,6 +340,14 @@ function settings_post(&$a) { $defperms += $_POST['def_view_storage']; if(x($_POST['def_write_storage'])) $defperms += $_POST['def_write_storage']; + if(x($_POST['def_view_pages'])) + $defperms += $_POST['def_view_pages']; + if(x($_POST['def_write_pages'])) + $defperms += $_POST['def_write_pages']; + if(x($_POST['def_republish'])) + $defperms += $_POST['def_republish']; + if(x($_POST['def_bookmark'])) + $defperms += $_POST['def_bookmark']; $notify = 0; @@ -394,20 +369,24 @@ function settings_post(&$a) { $notify += intval($_POST['notify8']); + $channel = $a->get_channel(); + $err = ''; $name_change = false; - if($username != $a->user['username']) { + if($username != $channel['channel_name']) { $name_change = true; - if(strlen($username) > 40) - $err .= t(' Please use a shorter name.'); - if(strlen($username) < 3) - $err .= t(' Name too short.'); + require_once('include/identity.php'); + $err = validate_channelname($username); + if($err) { + notice($err); + return; + } } - if($timezone != $a->user['timezone']) { + if($timezone != $channel['channel_timezone']) { if(strlen($timezone)) date_default_timezone_set($timezone); } @@ -417,61 +396,25 @@ function settings_post(&$a) { $str_group_deny = perms2str($_POST['group_deny']); $str_contact_deny = perms2str($_POST['contact_deny']); - set_pconfig(local_user(),'expire','items', $expire_items); - set_pconfig(local_user(),'expire','notes', $expire_notes); - set_pconfig(local_user(),'expire','starred', $expire_starred); - set_pconfig(local_user(),'expire','photos', $expire_photos); - set_pconfig(local_user(),'expire','network_only', $expire_network_only); - + set_pconfig(local_user(),'system','use_browser_location',$allow_location); set_pconfig(local_user(),'system','suggestme', $suggestme); set_pconfig(local_user(),'system','post_newfriend', $post_newfriend); set_pconfig(local_user(),'system','post_joingroup', $post_joingroup); set_pconfig(local_user(),'system','post_profilechange', $post_profilechange); - -/* - if($page_flags == PAGE_PRVGROUP) { - $hidewall = 1; - if((! $str_contact_allow) && (! $str_group_allow) && (! $str_contact_deny) && (! $str_group_deny)) { - if($def_gid) { - info( t('Private forum has no privacy permissions. Using default privacy group.'). EOL); - $str_group_allow = '<' . $def_gid . '>'; - } - else { - notice( t('Private forum has no privacy permissions and no default privacy group.') . EOL); - } - } - } - -*/ - -/* - $r = q("UPDATE `user` SET `username` = '%s', `email` = '%s', `openid` = '%s', `timezone` = '%s', `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s', `notify-flags` = %d, `page-flags` = %d, `default-location` = '%s', `allow_location` = %d, `maxreq` = %d, `expire` = %d, `openidserver` = '%s', `def_gid` = %d, `blockwall` = %d, `hidewall` = %d, `blocktags` = %d, `unkmail` = %d, `cntunkmail` = %d WHERE `uid` = %d LIMIT 1", - dbesc($username), - dbesc($email), - dbesc($openid), - dbesc($timezone), - dbesc($str_contact_allow), - dbesc($str_group_allow), - dbesc($str_contact_deny), - dbesc($str_group_deny), - intval($notify), - intval($page_flags), - dbesc($defloc), - intval($allow_location), - intval($maxreq), - intval($expire), - dbesc($openidserver), - intval($def_gid), - intval($blockwall), - intval($hidewall), - intval($blocktags), - intval($unkmail), - intval($cntunkmail), - intval(local_user()) - ); -*/ - - $r = q("update channel set channel_r_stream = %d, channel_r_profile = %d, channel_r_photos = %d, channel_r_abook = %d, channel_w_stream = %d, channel_w_wall = %d, channel_w_tagwall = %d, channel_w_comment = %d, channel_w_mail = %d, channel_w_photos = %d, channel_w_chat = %d, channel_a_delegate = %d where channel_id = %d limit 1", + set_pconfig(local_user(),'system','blocktags',$blocktags); + set_pconfig(local_user(),'system','hide_online_status',$hide_presence); + set_pconfig(local_user(),'system','channel_menu',$channel_menu); + + $r = q("update channel set channel_name = '%s', channel_pageflags = %d, channel_timezone = '%s', channel_location = '%s', channel_notifyflags = %d, channel_max_anon_mail = %d, channel_max_friend_req = %d, channel_expire_days = %d, channel_default_group = '%s', channel_r_stream = %d, channel_r_profile = %d, channel_r_photos = %d, channel_r_abook = %d, channel_w_stream = %d, channel_w_wall = %d, channel_w_tagwall = %d, channel_w_comment = %d, channel_w_mail = %d, channel_w_photos = %d, channel_w_chat = %d, channel_a_delegate = %d, channel_r_storage = %d, channel_w_storage = %d, channel_r_pages = %d, channel_w_pages = %d, channel_a_republish = %d, channel_a_bookmark = %d, channel_allow_cid = '%s', channel_allow_gid = '%s', channel_deny_cid = '%s', channel_deny_gid = '%s' where channel_id = %d limit 1", + dbesc($username), + intval($pageflags), + dbesc($timezone), + dbesc($defloc), + intval($notify), + intval($unkmail), + intval($maxreq), + intval($expire), + dbesc($def_group), intval($arr['channel_r_stream']), intval($arr['channel_r_profile']), intval($arr['channel_r_photos']), @@ -484,9 +427,18 @@ function settings_post(&$a) { intval($arr['channel_w_photos']), intval($arr['channel_w_chat']), intval($arr['channel_a_delegate']), + intval($arr['channel_r_storage']), + intval($arr['channel_w_storage']), + intval($arr['channel_r_pages']), + intval($arr['channel_w_pages']), + intval($arr['channel_a_republish']), + intval($arr['channel_a_bookmark']), + dbesc($str_contact_allow), + dbesc($str_group_allow), + dbesc($str_contact_deny), + dbesc($str_group_deny), intval(local_user()) ); - if($r) info( t('Settings updated.') . EOL); @@ -499,24 +451,22 @@ function settings_post(&$a) { intval(local_user()) ); - -// if($name_change) { -// q("UPDATE `contact` SET `name` = '%s', `name_date` = '%s' WHERE `uid` = %d AND `self` = 1 LIMIT 1", -// dbesc($username), -// dbesc(datetime_convert()), -// intval(local_user()) -// ); -// } - -// if(($old_visibility != $net_publish) || ($page_flags != $old_page_flags)) { - // Update global directory in background - $url = $_SESSION['my_url']; -// if($url && strlen(get_config('system','directory_submit_url'))) - + if($name_change) { + $r = q("update xchan set xchan_name = '%s', xchan_name_date = '%s' where xchan_hash = '%s' limit 1", + dbesc($username), + dbesc(datetime_convert()), + dbesc($channel['channel_hash']) + ); + $r = q("update profile set name = '%s' where uid = %d and is_default = 1", + dbesc($username), + intval($channel['channel_id']) + ); + } proc_run('php','include/directory.php',local_user()); -// } + build_sync_packet(); + //$_SESSION['theme'] = $theme; if($email_changed && $a->config['system']['register_policy'] == REGISTER_VERIFY) { @@ -540,9 +490,14 @@ function settings_content(&$a) { if(! local_user()) { notice( t('Permission denied.') . EOL ); - return; + return login(); } + + $channel = $a->get_channel(); + if($channel) + head_set_icon($channel['xchan_photo_s']); + // if(x($_SESSION,'submanage') && intval($_SESSION['submanage'])) { // notice( t('Permission denied.') . EOL ); // return; @@ -559,11 +514,11 @@ function settings_content(&$a) { '$title' => t('Add application'), '$submit' => t('Submit'), '$cancel' => t('Cancel'), - '$name' => array('name', t('Name'), '', ''), - '$key' => array('key', t('Consumer Key'), '', ''), - '$secret' => array('secret', t('Consumer Secret'), '', ''), - '$redirect' => array('redirect', t('Redirect'), '', ''), - '$icon' => array('icon', t('Icon url'), '', ''), + '$name' => array('name', t('Name'), '', t('Name of application')), + '$key' => array('key', t('Consumer Key'), random_string(16), t('Automatically generated - change if desired. Max length 20')), + '$secret' => array('secret', t('Consumer Secret'), random_string(16), t('Automatically generated - change if desired. Max length 20')), + '$redirect' => array('redirect', t('Redirect'), '', t('Redirect URI - leave blank unless your application specifically requires this')), + '$icon' => array('icon', t('Icon url'), '', t('Optional')), )); return $o; } @@ -629,20 +584,20 @@ function settings_content(&$a) { return $o; } - if((argc() > 1) && (argv(1) === 'addon')) { + if((argc() > 1) && (argv(1) === 'featured')) { $settings_addons = ""; $r = q("SELECT * FROM `hook` WHERE `hook` = 'plugin_settings' "); if(! count($r)) - $settings_addons = t('No Plugin settings configured'); + $settings_addons = t('No feature settings configured'); - call_hooks('plugin_settings', $settings_addons); + call_hooks('feature_settings', $settings_addons); $tpl = get_markup_template("settings_addons.tpl"); $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("settings_addon"), - '$title' => t('Plugin Settings'), + '$form_security_token' => get_form_security_token("settings_featured"), + '$title' => t('Feature Settings'), '$settings_addons' => $settings_addons )); return $o; @@ -681,7 +636,6 @@ function settings_content(&$a) { if((argc() > 1) && (argv(1) === 'features')) { - $arr = array(); $features = get_features(); @@ -689,7 +643,7 @@ function settings_content(&$a) { $arr[$fname] = array(); $arr[$fname][0] = $fdata[0]; foreach(array_slice($fdata,1) as $f) { - $arr[$fname][1][] = array('feature_' .$f[0],$f[1],((intval(get_pconfig(local_user(),'feature',$f[0]))) ? "1" : ''),$f[2],array(t('Off'),t('On'))); + $arr[$fname][1][] = array('feature_' .$f[0],$f[1],((intval(feature_enabled(local_user(),$f[0]))) ? "1" : ''),$f[2],array(t('Off'),t('On'))); } } @@ -701,6 +655,7 @@ function settings_content(&$a) { '$submit' => t('Submit'), '$field_yesno' => 'field_yesno.tpl', )); + return $o; } @@ -736,7 +691,7 @@ function settings_content(&$a) { $default_theme = get_config('system','theme'); if(! $default_theme) $default_theme = 'default'; - $default_mobile_theme = get_config('system','mobile-theme'); + $default_mobile_theme = get_config('system','mobile_theme'); if(! $mobile_default_theme) $mobile_default_theme = 'none'; @@ -759,7 +714,7 @@ function settings_content(&$a) { $unsupported = file_exists('view/theme/' . $th . '/unsupported'); $is_mobile = file_exists('view/theme/' . $th . '/mobile'); if (!$is_experimental or ($is_experimental && (get_config('experimentals','exp_themes')==1 or get_config('experimentals','exp_themes')===false))){ - $theme_name = (($is_experimental) ? sprintf("%s - \x28Experimental\x29", $f) : $f); + $theme_name = (($is_experimental) ? sprintf(t('%s - (Experimental)'), $f) : $f); if($is_mobile) { $mobile_themes[$f]=$theme_name; } @@ -770,18 +725,17 @@ function settings_content(&$a) { } } $theme_selected = (!x($_SESSION,'theme')? $default_theme : $_SESSION['theme']); - $mobile_theme_selected = (!x($_SESSION,'mobile-theme')? $default_mobile_theme : $_SESSION['mobile-theme']); + $mobile_theme_selected = (!x($_SESSION,'mobile_theme')? $default_mobile_theme : $_SESSION['mobile_theme']); $browser_update = intval(get_pconfig(local_user(), 'system','update_interval')); $browser_update = (($browser_update == 0) ? 40 : $browser_update / 1000); // default if not set: 40 seconds $itemspage = intval(get_pconfig(local_user(), 'system','itemspage')); - $itemspage = (($itemspage > 0 && $itemspage < 101) ? $itemspage : 40); // default if not set: 40 items + $itemspage = (($itemspage > 0 && $itemspage < 101) ? $itemspage : 20); // default if not set: 20 items $nosmile = get_pconfig(local_user(),'system','no_smilies'); $nosmile = (($nosmile===false)? '0': $nosmile); // default if not set: 0 - $theme_config = ""; if( ($themeconfigfile = get_theme_config_file($theme_selected)) != null){ require_once($themeconfigfile); @@ -801,7 +755,7 @@ function settings_content(&$a) { '$ajaxint' => array('browser_update', t("Update browser every xx seconds"), $browser_update, t('Minimum of 10 seconds, no maximum')), '$itemspage' => array('itemspage', t("Maximum number of conversations to load at any time:"), $itemspage, t('Maximum of 100 items')), '$nosmile' => array('nosmile', t("Don't show emoticons"), $nosmile, ''), - + '$layout_editor' => t('System Page Layout Editor - (advanced)'), '$theme_config' => $theme_config, )); @@ -838,9 +792,11 @@ function settings_content(&$a) { $perm_opts = array( array( t('Nobody except yourself'), 0), array( t('Only those you specifically allow'), PERMS_SPECIFIC), - array( t('Anybody in your address book'), PERMS_CONTACTS), + array( t('Approved connections'), PERMS_CONTACTS), + array( t('Any connections'), PERMS_PENDING), array( t('Anybody on this website'), PERMS_SITE), array( t('Anybody in this network'), PERMS_NETWORK), + array( t('Anybody authenticated'), PERMS_AUTHED), array( t('Anybody on the internet'), PERMS_PUBLIC) ); @@ -867,13 +823,16 @@ function settings_content(&$a) { $defloc = $channel['channel_location']; $maxreq = $channel['channel_max_friend_req']; - $expire = get_pconfig(local_user(),'expire','content_expire_days'); + $expire = $channel['channel_expire_days']; + $adult_flag = intval($channel['channel_pageflags'] & PAGE_ADULT); $blockwall = $a->user['blockwall']; - $blocktags = $a->user['blocktags']; $unkmail = $a->user['unkmail']; $cntunkmail = $a->user['cntunkmail']; + $hide_presence = intval(get_pconfig(local_user(), 'system','hide_online_status')); + + $expire_items = get_pconfig(local_user(), 'expire','items'); $expire_items = (($expire_items===false)? '1' : $expire_items); // default if not set: 1 @@ -902,85 +861,28 @@ function settings_content(&$a) { $post_profilechange = get_pconfig(local_user(), 'system','post_profilechange'); $post_profilechange = (($post_profilechange===false)? '0': $post_profilechange); // default if not set: 0 + $blocktags = get_pconfig(local_user(),'system','blocktags'); + $blocktags = (($blocktags===false) ? '0' : $blocktags); $timezone = date_default_timezone_get(); - $pageset_tpl = get_markup_template('pagetypes.tpl'); - $pagetype = replace_macros($pageset_tpl,array( - '$page_normal' => array('page-flags', t('Normal Account Page'), PAGE_NORMAL, - t('This account is a normal personal profile'), - ($a->user['page-flags'] == PAGE_NORMAL)), - - '$page_soapbox' => array('page-flags', t('Soapbox Page'), PAGE_SOAPBOX, - t('Automatically approve all connection/friend requests as read-only fans'), - ($a->user['page-flags'] == PAGE_SOAPBOX)), - - '$page_community' => array('page-flags', t('Community Forum/Celebrity Account'), PAGE_COMMUNITY, - t('Automatically approve all connection/friend requests as read-write fans'), - ($a->user['page-flags'] == PAGE_COMMUNITY)), - - '$page_freelove' => array('page-flags', t('Automatic Friend Page'), PAGE_FREELOVE, - t('Automatically approve all connection/friend requests as friends'), - ($a->user['page-flags'] == PAGE_FREELOVE)), - - '$page_prvgroup' => array('page-flags', t('Private Forum [Experimental]'), PAGE_PRVGROUP, - t('Private forum - approved members only'), - ($a->user['page-flags'] == PAGE_PRVGROUP)), - - - )); - - $opt_tpl = get_markup_template("field_yesno.tpl"); if(get_config('system','publish_all')) { $profile_in_dir = '<input type="hidden" name="profile_in_directory" value="1" />'; } else { $profile_in_dir = replace_macros($opt_tpl,array( - '$field' => array('profile_in_directory', t('Publish your default profile in your local site directory?'), $profile['publish'], '', array(t('No'),t('Yes'))), + '$field' => array('profile_in_directory', t('Publish your default profile in the network directory'), $profile['publish'], '', array(t('No'),t('Yes'))), )); } - $profile_in_net_dir = ''; - - - $hide_friends = replace_macros($opt_tpl,array( - '$field' => array('hide_friends', t('Hide your contact/friend list from viewers of your default profile?'), $profile['hide_friends'], '', array(t('No'),t('Yes'))), - )); - - $hide_wall = replace_macros($opt_tpl,array( - '$field' => array('hidewall', t('Hide your profile details from unknown viewers?'), $a->user['hidewall'], '', array(t('No'),t('Yes'))), - - )); - - $blockwall = replace_macros($opt_tpl,array( - '$field' => array('blockwall', t('Allow friends to post to your profile page?'), (intval($a->user['blockwall']) ? '0' : '1'), '', array(t('No'),t('Yes'))), - - )); - - - $blocktags = replace_macros($opt_tpl,array( - '$field' => array('blocktags', t('Allow friends to tag your posts?'), (intval($a->user['blocktags']) ? '0' : '1'), '', array(t('No'),t('Yes'))), - - )); - - $suggestme = replace_macros($opt_tpl,array( '$field' => array('suggestme', t('Allow us to suggest you as a potential friend to new members?'), $suggestme, '', array(t('No'),t('Yes'))), )); - - $unkmail = replace_macros($opt_tpl,array( - '$field' => array('unkmail', t('Permit unknown people to send you private mail?'), $unkmail, '', array(t('No'),t('Yes'))), - - )); - - $invisible = ((! $profile['publish']) ? true : false); - - $subdir = ((strlen($a->get_path())) ? '<br />' . t('or') . ' ' . $a->get_baseurl(true) . '/channel/' . $nickname : ''); $tpl_addr = get_markup_template("settings_nick_set.tpl"); @@ -994,25 +896,30 @@ function settings_content(&$a) { $stpl = get_markup_template('settings.tpl'); - $celeb = ((($a->user['page-flags'] == PAGE_SOAPBOX) || ($a->user['page-flags'] == PAGE_COMMUNITY)) ? true : false); - - $expire_arr = array( - 'days' => array('expire', t("Automatically expire posts after this many days:"), $expire, t('If empty, posts will not expire. Expired posts will be deleted')), - 'advanced' => t('Advanced expiration settings'), - 'label' => t('Advanced Expiration'), - 'items' => array('expire_items', t("Expire posts:"), $expire_items, '', array(t('No'),t('Yes'))), - 'notes' => array('expire_notes', t("Expire personal notes:"), $expire_notes, '', array(t('No'),t('Yes'))), - 'starred' => array('expire_starred', t("Expire starred posts:"), $expire_starred, '', array(t('No'),t('Yes'))), - 'photos' => array('expire_photos', t("Expire photos:"), $expire_photos, '', array(t('No'),t('Yes'))), - 'network_only' => array('expire_network_only', t("Only expire posts by others:"), $expire_network_only, '', array(t('No'),t('Yes'))), - ); - - + $celeb = false; + $perm_defaults = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); require_once('include/group.php'); - $group_select = mini_group_select(local_user(),$a->user['def_gid']); + $group_select = mini_group_select(local_user(),$channel['channel_default_group']); + + require_once('include/menu.php'); + $m1 = menu_list(local_user()); + $menu = false; + if($m1) { + $menu = array(); + $current = get_pconfig(local_user(),'system','channel_menu'); + $menu[] = array('name' => '', 'selected' => ((! $current) ? true : false)); + foreach($m1 as $m) { + $menu[] = array('name' => htmlspecialchars($m['menu_name'],ENT_COMPAT,'UTF-8'), 'selected' => (($m['menu_name'] === $current) ? ' selected="selected" ' : false)); + } + } $o .= replace_macros($stpl,array( '$ptitle' => t('Channel Settings'), @@ -1028,34 +935,40 @@ function settings_content(&$a) { '$username' => array('username', t('Full Name:'), $username,''), '$email' => array('email', t('Email Address:'), $email, ''), '$timezone' => array('timezone_select' , t('Your Timezone:'), select_timezone($timezone), ''), - '$defloc' => array('defloc', t('Default Post Location:'), $defloc, ''), - '$allowloc' => array('allow_location', t('Use Browser Location:'), ($a->user['allow_location'] == 1), ''), + '$defloc' => array('defloc', t('Default Post Location:'), $defloc, t('Geographical location to display on your posts')), + '$allowloc' => array('allow_location', t('Use Browser Location:'), ((get_pconfig(local_user(),'system','use_browser_location')) ? 1 : ''), ''), + '$adult' => array('adult', t('Adult Content'), $adult_flag, t('This channel frequently or regularly publishes adult content. (Please tag any adult material and/or nudity with #NSFW)')), '$h_prv' => t('Security and Privacy Settings'), + '$hide_presence' => array('hide_presence', t('Hide my online presence'),$hide_presence, t('Prevents displaying in your profile that you are online')), + + '$lbl_pmacro' => t('Simple Privacy Settings:'), + '$pmacro3' => t('Very Public - <em>extremely permissive (should be used with caution)</em>'), + '$pmacro2' => t('Typical - <em>default public, privacy when desired (similar to social network permissions but with improved privacy)</em>'), + '$pmacro1' => t('Private - <em>default private, never open or public</em>'), + '$pmacro0' => t('Blocked - <em>default blocked to/from everybody</em>'), '$permiss_arr' => $permiss, + '$blocktags' => array('blocktags',t('Allow others to tag your posts'), 1-$blocktags, t('Often used by the community to retro-actively flag inappropriate content'),array(t('No'),t('Yes'))), - '$maxreq' => array('maxreq', t('Maximum Friend Requests/Day:'), $maxreq ,t("\x28to prevent spam abuse\x29")), + '$lbl_p2macro' => t('Advanced Privacy Settings'), + + '$expire' => array('expire',t('Expire other channel content after this many days'),$expire,t('0 or blank prevents expiration')), + '$maxreq' => array('maxreq', t('Maximum Friend Requests/Day:'), intval($channel['channel_max_friend_req']) , t('May reduce spam activity')), '$permissions' => t('Default Post Permissions'), '$permdesc' => t("\x28click to open/close\x29"), - '$visibility' => $profile['net-publish'], - '$aclselect' => populate_acl($a->user,$celeb), + '$aclselect' => populate_acl($perm_defaults,false), '$suggestme' => $suggestme, - '$blockwall'=> $blockwall, // array('blockwall', t('Allow friends to post to your profile page:'), !$blockwall, ''), - '$blocktags'=> $blocktags, // array('blocktags', t('Allow friends to tag your posts:'), !$blocktags, ''), '$group_select' => $group_select, - '$expire' => $expire_arr, - '$profile_in_dir' => $profile_in_dir, - '$profile_in_net_dir' => $profile_in_net_dir, '$hide_friends' => $hide_friends, '$hide_wall' => $hide_wall, '$unkmail' => $unkmail, - '$cntunkmail' => array('cntunkmail', t('Maximum private messages per day from unknown people:'), $cntunkmail ,t("\x28to prevent spam abuse\x29")), + '$cntunkmail' => array('cntunkmail', t('Maximum private messages per day from unknown people:'), intval($channel['channel_max_anon_mail']) ,t("Useful to reduce spamming")), '$h_not' => t('Notification Settings'), @@ -1064,8 +977,8 @@ function settings_content(&$a) { '$post_joingroup' => array('post_joingroup', t('joining a forum/community'), $post_joingroup, ''), '$post_profilechange' => array('post_profilechange', t('making an <em>interesting</em> profile change'), $post_profilechange, ''), '$lbl_not' => t('Send a notification email when:'), - '$notify1' => array('notify1', t('You receive an introduction'), ($notify & NOTIFY_INTRO), NOTIFY_INTRO, ''), - '$notify2' => array('notify2', t('Your introductions are confirmed'), ($notify & NOTIFY_CONFIRM), NOTIFY_CONFIRM, ''), + '$notify1' => array('notify1', t('You receive a connection request'), ($notify & NOTIFY_INTRO), NOTIFY_INTRO, ''), + '$notify2' => array('notify2', t('Your connections are confirmed'), ($notify & NOTIFY_CONFIRM), NOTIFY_CONFIRM, ''), '$notify3' => array('notify3', t('Someone writes on your profile wall'), ($notify & NOTIFY_WALL), NOTIFY_WALL, ''), '$notify4' => array('notify4', t('Someone writes a followup comment'), ($notify & NOTIFY_COMMENT), NOTIFY_COMMENT, ''), '$notify5' => array('notify5', t('You receive a private message'), ($notify & NOTIFY_MAIL), NOTIFY_MAIL, ''), @@ -1077,7 +990,11 @@ function settings_content(&$a) { '$h_advn' => t('Advanced Account/Page Type Settings'), '$h_descadvn' => t('Change the behaviour of this account for special situations'), '$pagetype' => $pagetype, - + '$expert' => feature_enabled(local_user(),'expert'), + '$hint' => t('Please enable expert mode (in <a href="settings/features">Settings > Additional features</a>) to adjust!'), + '$lbl_misc' => t('Miscellaneous Settings'), + '$menus' => $menu, + '$menu_desc' => t('Personal menu to display in your channel pages'), )); call_hooks('settings_form',$o); diff --git a/mod/setup.php b/mod/setup.php index b3649ca40..69e026056 100755 --- a/mod/setup.php +++ b/mod/setup.php @@ -4,7 +4,25 @@ $install_wizard_pass=1; function setup_init(&$a){ + + // Ensure that if somebody hasn't read the install documentation and doesn't have all + // the required modules or has a totally borked shared hosting provider and they can't + // figure out what the hell is going on - that we at least spit out an error message which + // we can inquire about when they write to tell us that our software doesn't work. + + // The worst thing we can do at this point is throw a white screen of death and rely on + // them knowing about servers and php modules and logfiles enough so that we can guess + // at the source of the problem. As ugly as it may be, we need to throw a technically worded + // PHP error message in their face. Once installation is complete application errors will + // throw a white screen because these error messages divulge information which can + // potentially be useful to hackers. + + error_reporting(E_ERROR | E_WARNING | E_PARSE ); + ini_set('log_errors','0'); + ini_set('display_errors', '1'); + + // $baseurl/setup/testrwrite to test if rewite in .htaccess is working if (argc() ==2 && argv(1)=="testrewrite") { echo "ok"; @@ -14,6 +32,7 @@ function setup_init(&$a){ if (x($_POST,'pass')) $install_wizard_pass = intval($_POST['pass']); + } function setup_post(&$a) { @@ -26,20 +45,25 @@ function setup_post(&$a) { break; // just in case return don't return :) case 3: $urlpath = $a->get_path(); - $dbhost = notags(trim($_POST['dbhost'])); - $dbuser = notags(trim($_POST['dbuser'])); - $dbpass = notags(trim($_POST['dbpass'])); - $dbdata = notags(trim($_POST['dbdata'])); - $phpath = notags(trim($_POST['phpath'])); - $adminmail = notags(trim($_POST['adminmail'])); - $siteurl = notags(trim($_POST['siteurl'])); - - require_once("dba.php"); + $dbhost = trim($_POST['dbhost']); + $dbport = intval(trim($_POST['dbport'])); + $dbuser = trim($_POST['dbuser']); + $dbpass = trim($_POST['dbpass']); + $dbdata = trim($_POST['dbdata']); + $phpath = trim($_POST['phpath']); + $adminmail = trim($_POST['adminmail']); + $siteurl = trim($_POST['siteurl']); + + require_once('include/dba/dba_driver.php'); unset($db); - $db = new dba($dbhost, $dbuser, $dbpass, $dbdata, true); + $db = dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, true); + if(! $db->connected) { + echo "Database Connect failed: " . $db->error; + killme(); + } /*if(get_db_errno()) { unset($db); - $db = new dba($dbhost, $dbuser, $dbpass, '', true); + $db = dba_factory($dbhost, $dbport, $dbuser, $dbpass, '', true); if(! get_db_errno()) { $r = q("CREATE DATABASE '%s'", @@ -47,7 +71,7 @@ function setup_post(&$a) { ); if($r) { unset($db); - $db = new dba($dbhost, $dbuser, $dbpass, $dbdata, true); + $db = new dba($dbhost, $dbport, $dbuser, $dbpass, $dbdata, true); } else { $a->data['db_create_failed']=true; } @@ -65,6 +89,7 @@ function setup_post(&$a) { case 4: $urlpath = $a->get_path(); $dbhost = notags(trim($_POST['dbhost'])); + $dbport = intval(notags(trim($_POST['dbport']))); $dbuser = notags(trim($_POST['dbuser'])); $dbpass = notags(trim($_POST['dbpass'])); $dbdata = notags(trim($_POST['dbdata'])); @@ -74,13 +99,27 @@ function setup_post(&$a) { $siteurl = notags(trim($_POST['siteurl'])); + if($siteurl != z_root()) { + $test = z_fetch_url($siteurl."/setup/testrewrite"); + if((! $test['success']) || ($test['body'] != 'ok')) { + $a->data['url_fail'] = true; + $a->data['url_error'] = $test['error']; + return; + } + } // connect to db - $db = new dba($dbhost, $dbuser, $dbpass, $dbdata, true); + $db = dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, true); + + if(! $db->connected) { + echo 'CRITICAL: DB not connected.'; + killme(); + } $tpl = get_intltext_template('htconfig.tpl'); $txt = replace_macros($tpl,array( '$dbhost' => $dbhost, + '$dbport' => $dbport, '$dbuser' => $dbuser, '$dbpass' => $dbpass, '$dbdata' => $dbdata, @@ -120,7 +159,7 @@ function setup_content(&$a) { global $install_wizard_pass, $db; $o = ''; $wizard_status = ""; - $install_title = t('Friendica Red Communications Server - Setup'); + $install_title = t('Red Matrix Server - Setup'); @@ -128,6 +167,13 @@ function setup_content(&$a) { $install_wizard_pass = 2; $wizard_status = t('Could not connect to database.'); } + if(x($a->data,'url_fail')) { + $install_wizard_pass = 3; + $wizard_status = t('Could not connect to specified site URL. Possible SSL certificate or DNS issue.'); + if($a->data['url_error']) + $wizard_status .= ' ' . $a->data['url_error']; + } + if(x($a->data,'db_create_failed')) { $install_wizard_pass = 2; $wizard_status = t('Could not create table.'); @@ -136,7 +182,7 @@ function setup_content(&$a) { $db_return_text=""; if(x($a->data,'db_installed')) { $txt = '<p style="font-size: 130%;">'; - $txt .= t('Your Friendica site database has been installed.') . EOL; + $txt .= t('Your site database has been installed.') . EOL; $db_return_text .= $txt; } @@ -148,7 +194,7 @@ function setup_content(&$a) { } if($db && $db->connected) { - $r = q("SELECT COUNT(*) as `total` FROM `user`"); + $r = q("SELECT COUNT(*) as `total` FROM `account`"); if($r && count($r) && $r[0]['total']) { $tpl = get_markup_template('install.tpl'); return replace_macros($tpl, array( @@ -183,6 +229,10 @@ function setup_content(&$a) { check_htconfig($checks); + check_smarty3($checks); + + check_store($checks); + check_keys($checks); if(x($_POST,'phpath')) @@ -220,6 +270,7 @@ function setup_content(&$a) { $dbhost = ((x($_POST,'dbhost')) ? notags(trim($_POST['dbhost'])) : 'localhost'); $dbuser = notags(trim($_POST['dbuser'])); + $dbport = intval(notags(trim($_POST['dbport']))); $dbpass = notags(trim($_POST['dbpass'])); $dbdata = notags(trim($_POST['dbdata'])); $phpath = notags(trim($_POST['phpath'])); @@ -231,13 +282,14 @@ function setup_content(&$a) { $o .= replace_macros($tpl, array( '$title' => $install_title, '$pass' => t('Database connection'), - '$info_01' => t('In order to install Friendica we need to know how to connect to your database.'), + '$info_01' => t('In order to install Red Matrix we need to know how to connect to your database.'), '$info_02' => t('Please contact your hosting provider or site administrator if you have questions about these settings.'), '$info_03' => t('The database you specify below should already exist. If it does not, please create it before continuing.'), '$status' => $wizard_status, - '$dbhost' => array('dbhost', t('Database Server Name'), $dbhost, ''), + '$dbhost' => array('dbhost', t('Database Server Name'), $dbhost, t('Default is localhost')), + '$dbport' => array('dbport', t('Database Port'), $dbport, t('Communication port number - use 0 for default')), '$dbuser' => array('dbuser', t('Database Login Name'), $dbuser, ''), '$dbpass' => array('dbpass', t('Database Login Password'), $dbpass, ''), '$dbdata' => array('dbdata', t('Database Name'), $dbdata, ''), @@ -258,8 +310,9 @@ function setup_content(&$a) { return $o; }; break; case 3: { // Site settings - require_once('datetime.php'); + require_once('include/datetime.php'); $dbhost = ((x($_POST,'dbhost')) ? notags(trim($_POST['dbhost'])) : 'localhost'); + $dbport = intval(notags(trim($_POST['dbuser']))); $dbuser = notags(trim($_POST['dbuser'])); $dbpass = notags(trim($_POST['dbpass'])); $dbdata = notags(trim($_POST['dbdata'])); @@ -277,6 +330,7 @@ function setup_content(&$a) { '$status' => $wizard_status, '$dbhost' => $dbhost, + '$dbport' => $dbport, '$dbuser' => $dbuser, '$dbpass' => $dbpass, '$dbdata' => $dbdata, @@ -322,13 +376,16 @@ function check_php(&$phpath, &$checks) { if (strlen($phpath)){ $passed = file_exists($phpath); } else { - $phpath = trim(shell_exec('which php')); + if(is_windows()) + $phpath = trim(shell_exec('where php')); + else + $phpath = trim(shell_exec('which php')); $passed = strlen($phpath); } $help = ""; if(!$passed) { $help .= t('Could not find a command line version of PHP in the web server PATH.'). EOL; - $help .= t("If you don't have a command line version of PHP installed on server, you will not be able to run background polling via cron. See <a href='http://friendica.com/node/27'>'Activating scheduled tasks'</a>") . EOL ; + $help .= t("If you don't have a command line version of PHP installed on server, you will not be able to run background polling via cron.") . EOL; $help .= EOL . EOL ; $tpl = get_markup_template('field_input.tpl'); $help .= replace_macros($tpl, array( @@ -385,6 +442,7 @@ function check_funcs(&$checks) { check_add($ck_funcs, t('OpenSSL PHP module'), true, true, ""); check_add($ck_funcs, t('mysqli PHP module'), true, true, ""); check_add($ck_funcs, t('mb_string PHP module'), true, true, ""); + check_add($ck_funcs, t('mcrypt PHP module'), true, true, ""); if(function_exists('apache_get_modules')){ @@ -394,6 +452,12 @@ function check_funcs(&$checks) { check_add($ck_funcs, t('Apache mod_rewrite module'), true, true, ""); } } + if((! function_exists('proc_open')) || strstr(ini_get('disable_functions'),'proc_open')) { + check_add($ck_funcs, t('proc_open'), false, true, t('Error: proc_open is required but is either not installed or has been disabled in php.ini')); + } + else { + check_add($ck_funcs, t('proc_open'), true, true, ""); + } if(! function_exists('curl_init')){ $ck_funcs[0]['status']= false; @@ -415,6 +479,10 @@ function check_funcs(&$checks) { $ck_funcs[4]['status']= false; $ck_funcs[4]['help']= t('Error: mb_string PHP module required but not installed.'); } + if(! function_exists('mcrypt_encrypt')){ + $ck_funcs[5]['status']= false; + $ck_funcs[5]['help']= t('Error: mcrypt PHP module required but not installed.'); + } $checks = array_merge($checks, $ck_funcs); @@ -431,7 +499,7 @@ function check_htconfig(&$checks) { $status=false; $help = t('The web installer needs to be able to create a file called ".htconfig.php" in the top folder of your web server and it is unable to do so.') .EOL; $help .= t('This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can.').EOL; - $help .= t('At the end of this procedure, we will give you a text to save in a file named .htconfig.php in your Friendica top folder.').EOL; + $help .= t('At the end of this procedure, we will give you a text to save in a file named .htconfig.php in your Red top folder.').EOL; $help .= t('You can alternatively skip this procedure and perform a manual installation. Please see the file "install/INSTALL.txt" for instructions.').EOL; } @@ -439,13 +507,77 @@ function check_htconfig(&$checks) { } +function check_smarty3(&$checks) { + $status = true; + $help = ""; + if( !is_writable('view/tpl/smarty3') ) { + + $status=false; + $help = t('Red uses the Smarty3 template engine to render its web views. Smarty3 compiles templates to PHP to speed up rendering.') .EOL; + $help .= t('In order to store these compiled templates, the web server needs to have write access to the directory view/tpl/smarty3/ under the Red top level folder.').EOL; + $help .= t('Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder.').EOL; + $help .= t('Note: as a security measure, you should give the web server write access to view/tpl/smarty3/ only--not the template files (.tpl) that it contains.').EOL; + } + + check_add($checks, t('view/tpl/smarty3 is writable'), $status, true, $help); + +} + +function check_store(&$checks) { + $status = true; + $help = ""; + + @mkdir('store',STORAGE_DEFAULT_PERMISSIONS); + + if( !is_writable('store') ) { + + $status=false; + $help = t('Red uses the store directory to save uploaded files. The web server needs to have write access to the store directory under the Red top level folder') . EOL; + $help .= t('Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder.').EOL; + } + + check_add($checks, t('store is writable'), $status, true, $help); + +} + + function check_htaccess(&$checks) { $a = get_app(); $status = true; $help = ""; + $ssl_error = false; + + $url = $a->get_baseurl() . '/setup/testrewrite'; + if (function_exists('curl_init')){ - $test = fetch_url($a->get_baseurl()."/setup/testrewrite"); - if ($test!="ok") { + $test = z_fetch_url($url); + if(! $test['success']) { + if(strstr($url,'https://')) { + $test = z_fetch_url($url,false,0,array('novalidate' => true)); + if($test['success']) { + $ssl_error = true; + } + } + else { + $test = z_fetch_url(str_replace('http://','https://',$url),false,0,array('novalidate' => true)); + if($test['success']) { + $ssl_error = true; + } + } + + if($ssl_error) { + $help = t('SSL certificate cannot be validated. Fix certificate or disable https access to this site.') . EOL; + $help .= t('If you have https access to your website or allow connections to TCP port 443 (the https: port), you MUST use a browser-valid certificate. You MUST NOT use self-signed certificates!') . EOL; + $help .= t('This restriction is incorporated because public posts from you may for example contain references to images on your own hub.') . EOL; + $help .= t('If your certificate is not recognised, members of other sites (who may themselves have valid certificates) will get a warning message on their own site complaining about security issues.') . EOL; + $help .= t('This can cause usability issues elsewhere (not just on your own site) so we must insist on this requirement.') .EOL; + $help .= t('Providers are available that issue free certificates which are browser-valid.'). EOL; + + check_add($checks, t('SSL certificate validation'),false,true, $help); + } + } + + if ((! $test['success']) || ($test['body'] != "ok")) { $status = false; $help = t('Url rewrite in .htaccess is not working. Check your server configuration.'); } @@ -458,7 +590,7 @@ function check_htaccess(&$checks) { function manual_config(&$a) { - $data = htmlentities($a->data['txt']); + $data = htmlspecialchars($a->data['txt'],ENT_COMPAT,'UTF-8'); $o = t('The database configuration file ".htconfig.php" could not be written. Please use the enclosed text to create a configuration file in your web server root.'); $o .= "<textarea rows=\"24\" cols=\"80\" >$data</textarea>"; return $o; @@ -492,13 +624,37 @@ function load_database($db) { function what_next() { $a = get_app(); + // install the standard theme + set_config('system','allowed_themes','redbasic'); + + // Set a lenient list of ciphers if using openssl. Other ssl engines + // (e.g. NSS used in RedHat) require different syntax, so hopefully + // the default curl cipher list will work for most sites. If not, + // this can set via config. Many distros are now disabling RC4, + // but many Red sites still use it and are unable to change it. + // We do not use SSL for encryption, only to protect session cookies. + // z_fetch_url() is also used to import shared links and other content + // so in theory most any cipher could show up and we should do our best + // to make the content available rather than tell folks that there's a + // weird SSL error which they can't do anything about. + + $x = curl_version(); + if(stristr($x['ssl_version'],'openssl')) + set_config('system','curl_ssl_ciphers','ALL:!eNULL'); + + + // Create a system channel + require_once ('include/identity.php'); + create_sys_channel(); + + $baseurl = $a->get_baseurl(); return t('<h1>What next</h1>') ."<p>".t('IMPORTANT: You will need to [manually] setup a scheduled task for the poller.') .t('Please see the file "install/INSTALL.txt".') ."</p><p>" - .t("Go to your new Friendica node <a href='$baseurl/register'>registration page</a> and register as new user. Remember to use the same email you have entered as administrator email. This will allow you to enter the site admin panel.") + .t("Go to your new Red node <a href='$baseurl/register'>registration page</a> and register as new user. Remember to use the same email you have entered as administrator email. This will allow you to enter the site admin panel.") ."</p>"; } diff --git a/mod/share.php b/mod/share.php index 33aa9eede..8b0403663 100644 --- a/mod/share.php +++ b/mod/share.php @@ -1,31 +1,81 @@ <?php +require_once('include/security.php'); require_once('bbcode.php'); function share_init(&$a) { $post_id = ((argc() > 1) ? intval(argv(1)) : 0); - if((! $post_id) || (! local_user())) + + if(! $post_id) + killme(); + + if(! (local_user() || remote_user())) killme(); - $r = q("SELECT * from item WHERE id = %d AND uid = %d and item_restrict = 0 LIMIT 1", - intval($post_id), - intval(local_user()) + + $r = q("SELECT * from item WHERE id = %d LIMIT 1", + intval($post_id) ); if((! $r) || $r[0]['item_private']) killme(); + $sql_extra = item_permissions_sql($r[0]['uid']); + + $r = q("select * from item where id = %d $sql_extra", + intval($post_id) + ); + if(! $r) + killme(); + + // FIXME - we only share bbcode + + if($r[0]['mimetype'] !== 'text/bbcode') + killme(); + + // FIXME - eventually we want to post remotely via rpost + // on your home site. + // When that works remove this next bit: + + if(! local_user()) + killme(); + xchan_query($r); - $o = '[share]' . "\n"; + if (strpos($r[0]['body'], "[/share]") !== false) { + $pos = strpos($r[0]['body'], "[share"); + $o = substr($r[0]['body'], $pos); + } else { + $o = "[share author='".urlencode($r[0]['author']['xchan_name']). + "' profile='".$r[0]['author']['xchan_url'] . + "' avatar='".$r[0]['author']['xchan_photo_s']. + "' link='".$r[0]['plink']. + "' posted='".$r[0]['created']. + "' message_id='".$r[0]['mid']."']\n"; + if($r[0]['title']) + $o .= '[b]'.$r[0]['title'].'[/b]'."\n"; + $o .= $r[0]['body']; + $o.= "[/share]"; + } - $o .= "\xE2\x99\xb2" . ' [url=' . $r[0]['author']['xchan_url'] . ']' . $r[0]['author']['xchan_name'] . '[/url]' . "\n"; - if($r[0]['title']) - $o .= '[b]' . $r[0]['title'] . '[/b]' . "\n"; - $o .= $r[0]['body'] . "\n" ; + if(local_user()) { + echo $o; + killme(); + } + + $observer = $a->get_observer(); + $parsed = $observer['xchan_url']; + if($parsed) { + $post_url = $parsed['scheme'] . ':' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : '') + . '/rpost'; + // FIXME - we were probably called from JS + // so we don't know the return page. + // in fact we won't be able to load the remote page. + // we might need an iframe - $o .= (($r[0]['plink']) ? '[url=' . $r[0]['plink'] . ']' . t('link') . '[/url]' . "\n" : '') . '[/share]'; + $x = z_post_url($post_url, array('f' => '', 'body' => $o )); + killme(); + } + - echo $o; - killme(); } diff --git a/mod/siteinfo.php b/mod/siteinfo.php index 0cd569d20..bdf9b1af6 100644 --- a/mod/siteinfo.php +++ b/mod/siteinfo.php @@ -27,14 +27,20 @@ function siteinfo_init(&$a) { $visible_plugins[] = $rr['name']; } + if(@is_dir('.git') && function_exists('shell_exec')) + $commit = @shell_exec('git log -1 --format="%h"'); + if(! isset($commit) || strlen($commit) > 16) + $commit = ''; + $data = Array( - 'version' => FRIENDICA_VERSION, + 'version' => RED_VERSION, + 'commit' => $commit, 'url' => z_root(), 'plugins' => $visible_plugins, 'register_policy' => $register_policy[$a->config['system']['register_policy']], 'admin' => $admin, 'site_name' => $a->config['sitename'], - 'platform' => FRIENDICA_PLATFORM, + 'platform' => RED_PLATFORM, 'info' => ((x($a->config,'info')) ? $a->config['info'] : '') ); @@ -47,27 +53,16 @@ function siteinfo_init(&$a) { function siteinfo_content(&$a) { - // FIXME Gak - this needs to be a template. - - $o = ''; - $o .= '<h3>' . t('Red') . '</h3>'; - - - $o .= '<p></p><p>'; - - $o .= t('This is Red - another decentralized, distributed communications project by the folks at Friendica.'); - if(! get_config('system','hidden_version_siteinfo')) - $o .= '</p><p>' . sprintf( t('Version %s'), FRIENDICA_VERSION ) . '</p><p>'; - $o .= '</p><p>'; - $o .= t('Running at web location') . ' ' . z_root() . '</p><p>'; - - $o .= t('Please visit <a href="http://friendica.com">Friendica.com</a> to learn more about the Friendica and/or Red project.') . '</p><p>'; - - $o .= t('Bug reports and issues: please visit') . ' ' . '<a href="http://bugs.friendica.com">Bugs.Friendica.com</a></p><p>'; - $o .= t('Suggestions, praise, donations, etc. - please email "Info" at Friendica - dot com') . '</p>'; - - $o .= '<p></p>'; - + if(! get_config('system','hidden_version_siteinfo')) { + $version = sprintf( t('Version %s'), RED_VERSION ); + if(@is_dir('.git') && function_exists('shell_exec')) + $commit = @shell_exec('git log -1 --format="%h"'); + if(! isset($commit) || strlen($commit) > 16) + $commit = ''; + } + else { + $version = $commit = ''; + } $visible_plugins = array(); if(is_array($a->plugins) && count($a->plugins)) { $r = q("select * from addon where hidden = 0"); @@ -76,9 +71,9 @@ function siteinfo_content(&$a) { $visible_plugins[] = $rr['name']; } - + $plugins_list = ''; if(count($visible_plugins)) { - $o .= '<p>' . t('Installed plugins/addons/apps:') . '</p>'; + $plugins_text = t('Installed plugins/addons/apps:'); $sorted = $visible_plugins; $s = ''; sort($sorted); @@ -88,10 +83,33 @@ function siteinfo_content(&$a) { $s .= $p; } } - $o .= '<div style="margin-left: 25px; margin-right: 25px;">' . $s . '</div>'; + $plugins_list .= $s; } else - $o .= '<p>' . t('No installed plugins/addons/apps') . '</p>'; + $plugins_text = t('No installed plugins/addons/apps'); + + $admininfo = bbcode(get_config('system','admininfo')); + + if(file_exists('doc/site_donate.html')) + $donate .= file_get_contents('doc/site_donate.html'); + + $o = replace_macros(get_markup_template('siteinfo.tpl'), array( + '$title' => t('Red'), + '$description' => t('This is a hub of the Red Matrix - a global cooperative network of decentralised privacy enhanced websites.'), + '$version' => $version, + '$commit' => $commit, + '$web_location' => t('Running at web location') . ' ' . z_root(), + '$visit' => t('Please visit <a href="http://getzot.com">GetZot.com</a> to learn more about the Red Matrix.'), + '$bug_text' => t('Bug reports and issues: please visit'), + '$bug_link_url' => 'https://github.com/friendica/red/issues', + '$bug_link_text' => 'redmatrix issues', + '$contact' => t('Suggestions, praise, etc. - please email "redmatrix" at librelist - dot com'), + '$donate' => $donate, + '$adminlabel' => t('Site Administrators'), + '$admininfo' => $admininfo, + '$plugins_text' => $plugins_text, + '$plugins_list' => $plugins_list + )); call_hooks('about_hook', $o); diff --git a/mod/sitelist.php b/mod/sitelist.php new file mode 100644 index 000000000..1e6d0fcfb --- /dev/null +++ b/mod/sitelist.php @@ -0,0 +1,51 @@ +<?php /** @file */ + +function sitelist_init(&$a) { + + $start = (($_REQUEST['start']) ? intval($_REQUEST['start']) : 0); + $limit = ((intval($_REQUEST['limit'])) ? intval($_REQUEST['limit']) : 30); + $order = (($_REQUEST['order']) ? $_REQUEST['order'] : 'random'); + $open = (($_REQUEST['open']) ? intval($_REQUEST['open']) : false); + + + $sql_order = " order by site_url "; + if($order == 'random') + $sql_order = " order by rand() "; + + $sql_limit = " limit $start, $limit "; + + $sql_extra = ""; + if($open) + $sql_extra = " and site_register = " . intval(REGISTER_OPEN) . " "; + + + $result = array('success' => false); + + $r = q("select count(site_url) as total from site where 1 $sql_extra "); + + if($r) + $result['total'] = intval($r[0]['total']); + + $result['start'] = $start; + $result['limit'] = $limit; + + $r = q("select * from site where true $sql_extra $sql_order $sql_limit"); + + $result['results'] = 0; + $result['entries'] = array(); + + if($r) { + $result['success'] = true; + $result['results'] = count($r); + + foreach($r as $rr) { + $result['entries'][] = array('url' => $rr['site_url']); + } + + } + + echo json_encode($result); + killme(); + + +}
\ No newline at end of file diff --git a/mod/sources.php b/mod/sources.php new file mode 100644 index 000000000..f4b36508f --- /dev/null +++ b/mod/sources.php @@ -0,0 +1,168 @@ +<?php /** @file */ + +function sources_post(&$a) { + if(! local_user()) + return; + + if(! feature_enabled(local_user(),'channel_sources')) + return ''; + + $source = intval($_REQUEST['source']); + $xchan = $_REQUEST['xchan']; + $abook = intval($_REQUEST['abook']); + $words = $_REQUEST['words']; + $frequency = $_REQUEST['frequency']; + $name = $_REQUEST['name']; + + $channel = $a->get_channel(); + + if($name == '*') + $xchan = '*'; + + if($abook) { + $r = q("select abook_xchan from abook where abook_id = %d and abook_channel = %d limit 1", + intval($abook), + intval(local_user()) + ); + if($r) + $xchan = $r[0]['abook_xchan']; + } + + if(! $xchan) { + notice ( t('Failed to create source. No channel selected.') . EOL); + return; + } + + if(! $source) { + $r = q("insert into source ( src_channel_id, src_channel_xchan, src_xchan, src_patt ) + values ( %d, '%s', '%s', '%s' ) ", + intval(local_user()), + dbesc($channel['channel_hash']), + dbesc($xchan), + dbesc($words) + ); + if($r) { + info( t('Source created.') . EOL); + } + goaway(z_root() . '/sources'); + } + else { + $r = q("update source set src_xchan = '%s', src_patt = '%s' where src_channel_id = %d and src_id = %d limit 1", + dbesc($xchan), + dbesc($words), + intval(local_user()), + intval($source) + ); + if($r) { + info( t('Source updated.') . EOL); + } + + } +} + + +function sources_content(&$a) { + if(! local_user()) { + notice( t('Permission denied.') . EOL); + return ''; + } + + if(! feature_enabled(local_user(),'channel_sources')) { + return ''; + } + + // list sources + if(argc() == 1) { + $r = q("select source.*, xchan.* from source left join xchan on src_xchan = xchan_hash where src_channel_id = %d", + intval(local_user()) + ); + if($r) { + for($x = 0; $x < count($r); $x ++) { + if($r[$x]['src_xchan'] == '*') { + $r[$x]['xchan_name'] = t('*'); + } + $r[$x]['src_patt'] = htmlspecialchars($r[$x]['src_patt'], ENT_COMPAT,'UTF-8'); + } + } + $o = replace_macros(get_markup_template('sources_list.tpl'), array( + '$title' => t('Channel Sources'), + '$desc' => t('Manage remote sources of content for your channel.'), + '$new' => t('New Source'), + '$sources' => $r + )); + return $o; + } + + if(argc() == 2 && argv(1) === 'new') { + // TODO add the words 'or RSS feed' and corresponding code to manage feeds and frequency + + $o = replace_macros(get_markup_template('sources_new.tpl'), array( + '$title' => t('New Source'), + '$desc' => t('Import all or selected content from the following channel into this channel and distribute it according to your channel settings.'), + '$words' => array( 'words', t('Only import content with these words (one per line)'),'',t('Leave blank to import all public content')), + '$name' => array( 'name', t('Channel Name'), '', ''), + '$submit' => t('Submit') + )); + return $o; + + } + + if(argc() == 2 && intval(argv(1))) { + // edit source + $r = q("select source.*, xchan.* from source left join xchan on src_xchan = xchan_hash where src_id = %d and src_channel_id = %d limit 1", + intval(argv(1)), + intval(local_user()) + ); + if($r) { + $x = q("select abook_id from abook where abook_xchan = '%s' and abook_channel = %d limit 1", + dbesc($r[0]['src_xchan']), + intval(local_user()) + ); + } + if(! $r) { + notice( t('Source not found.') . EOL); + return ''; + } + + $r[0]['src_patt'] = htmlspecialchars($r[0]['src_patt'], ENT_QUOTES,'UTF-8'); + + $o = replace_macros(get_markup_template('sources_edit.tpl'), array( + '$title' => t('Edit Source'), + '$drop' => t('Delete Source'), + '$id' => $r[0]['src_id'], + '$desc' => t('Import all or selected content from the following channel into this channel and distribute it according to your channel settings.'), + '$words' => array( 'words', t('Only import content with these words (one per line)'),$r[0]['src_patt'],t('Leave blank to import all public content')), + '$xchan' => $r[0]['src_xchan'], + '$abook' => $x[0]['abook_id'], + '$name' => array( 'name', t('Channel Name'), $r[0]['xchan_name'], ''), + '$submit' => t('Submit') + )); + return $o; + + } + + if(argc() == 3 && intval(argv(1)) && argv(2) === 'drop') { + $r = q("select * from source where src_id = %d and src_channel_id = %d limit 1", + intval(argv(1)), + intval(local_user()) + ); + if(! $r) { + notice( t('Source not found.') . EOL); + return ''; + } + $r = q("delete from source where src_id = %d and src_channel_id = %d limit 1", + intval(argv(1)), + intval(local_user()) + ); + if($r) + info( t('Source removed') . EOL); + else + notice( t('Unable to remove source.') . EOL); + + goaway(z_root() . '/sources'); + + } + + // shouldn't get here. + +}
\ No newline at end of file diff --git a/mod/sslify.php b/mod/sslify.php new file mode 100644 index 000000000..ed06d87c1 --- /dev/null +++ b/mod/sslify.php @@ -0,0 +1,24 @@ +<?php + +function sslify_init(&$a) { + $x = z_fetch_url($_REQUEST['url']); + if($x['success']) { + $h = explode("\n",$x['headers']); + foreach ($h as $l) { + list($k,$v) = array_map("trim", explode(":", trim($l), 2)); + $hdrs[$k] = $v; + } + if (array_key_exists('Content-Type', $hdrs)) + $type = $hdrs['Content-Type']; + + header('Content-Type: ' . $type); + echo $x['body']; + killme(); + } + killme(); + // for some reason when this fallback is in place - it gets triggered + // often, (creating mixed content exceptions) even though there is + // nothing obvious missing on the page when we bypass it. + goaway($_REQUEST['url']); +} + diff --git a/mod/starred.php b/mod/starred.php index 530c5c7e0..ca7621b0f 100644 --- a/mod/starred.php +++ b/mod/starred.php @@ -19,13 +19,7 @@ function starred_init(&$a) { if(! count($r)) killme(); - $item_flags = $r[0]['item_flags']; - - if($item_flags & ITEM_STARRED) - $item_flags -= ITEM_STARRED; - else - $item_flags += ITEM_STARRED; - + $item_flags = ( $r[0]['item_flags'] ^ ITEM_STARRED ); $r = q("UPDATE item SET item_flags = %d WHERE uid = %d and id = %d LIMIT 1", intval($item_flags), diff --git a/mod/subthread.php b/mod/subthread.php index f8918e25d..5ef0615b1 100755 --- a/mod/subthread.php +++ b/mod/subthread.php @@ -7,20 +7,20 @@ require_once('include/items.php'); function subthread_content(&$a) { - if(! local_user() && ! remote_user()) { + if((! local_user()) && (! remote_user())) { return; } $activity = ACTIVITY_FOLLOW; - $item_id = (($a->argc > 1) ? notags(trim($a->argv[1])) : 0); + $item_id = ((argc() > 1) ? notags(trim(argv(1))) : 0); - $r = q("SELECT * FROM `item` WHERE `parent` = '%s' OR `parent-uri` = '%s' and parent = id LIMIT 1", + $r = q("SELECT * FROM `item` WHERE `parent` = '%s' OR `parent_mid` = '%s' and parent = id LIMIT 1", dbesc($item_id), dbesc($item_id) ); - if(! $item_id || (! count($r))) { + if((! $item_id) || (! $r)) { logger('subthread: no item ' . $item_id); return; } @@ -34,60 +34,146 @@ function subthread_content(&$a) { if(! perm_is_allowed($owner_uid,$ob_hash,'post_comments')) return; + $sys = get_sys_channel(); - $remote_owner = null; + $owner_uid = $item['uid']; + $owner_aid = $item['aid']; - if(! $item['wall']) { - // The top level post may have been written by somebody on another system - $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($item['contact-id']), - intval($item['uid']) - ); - if(! count($r)) - return; - if(! $r[0]['self']) - $remote_owner = $r[0]; + // if this is a "discover" item, (item['uid'] is the sys channel), + // fallback to the item comment policy, which should've been + // respected when generating the conversation thread. + // Even if the activity is rejected by the item owner, it should still get attached + // to the local discover conversation on this site. + + if(($owner_uid != $sys['channel_id']) && (! perm_is_allowed($owner_uid,$observer['xchan_hash'],'post_comments'))) { + notice( t('Permission denied') . EOL); + killme(); } - // this represents the post owner on this system. + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($item['owner_xchan']) + ); + if($r) + $thread_owner = $r[0]; + else + killme(); - $r = q("SELECT `contact`.*, `user`.`nickname` FROM `contact` LEFT JOIN `user` ON `contact`.`uid` = `user`.`uid` - WHERE `contact`.`self` = 1 AND `contact`.`uid` = %d LIMIT 1", - intval($owner_uid) + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($item['author_xchan']) ); - if(count($r)) - $owner = $r[0]; + if($r) + $item_author = $r[0]; + else + killme(); + + + $mid = item_message_id(); + + $post_type = (($item['resource_type'] === 'photo') ? t('photo') : t('status')); + + $links = array(array('rel' => 'alternate','type' => 'text/html', 'href' => $item['plink'])); + $objtype = (($item['resource_type'] === 'photo') ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE ); + + $body = $item['body']; + + $obj = json_encode(array( + 'type' => $objtype, + 'id' => $item['mid'], + 'parent' => (($item['thr_parent']) ? $item['thr_parent'] : $item['parent_mid']), + 'link' => $links, + 'title' => $item['title'], + 'content' => $item['body'], + 'created' => $item['created'], + 'edited' => $item['edited'], + 'author' => array( + 'name' => $item_author['xchan_name'], + 'address' => $item_author['xchan_addr'], + 'guid' => $item_author['xchan_guid'], + 'guid_sig' => $item_author['xchan_guid_sig'], + 'link' => array( + array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item_author['xchan_url']), + array('rel' => 'photo', 'type' => $item_author['xchan_photo_mimetype'], 'href' => $item_author['xchan_photo_m'])), + ), + )); + + if(! ($item['item_flags'] & ITEM_THREAD_TOP)) + $post_type = 'comment'; + + + $bodyverb = t('%1$s is following %2$s\'s %3$s'); + + $item_flags = ITEM_ORIGIN | ITEM_NOTSHOWN; + if($item['item_flags'] & ITEM_WALL) + $item_flags |= ITEM_WALL; + + + $arr = array(); + + $arr['mid'] = $mid; + $arr['aid'] = $owner_aid; + $arr['uid'] = $owner_uid; + $arr['item_flags'] = $item_flags; + $arr['parent'] = $item['id']; + $arr['parent_mid'] = $item['mid']; + $arr['thr_parent'] = $item['mid']; + $arr['owner_xchan'] = $thread_owner['xchan_hash']; + $arr['author_xchan'] = $observer['xchan_hash']; + + + $ulink = '[zrl=' . $item_author['xchan_url'] . ']' . $item_author['xchan_name'] . '[/zrl]'; + $alink = '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]'; + $plink = '[zrl=' . $a->get_baseurl() . '/display/' . $item['mid'] . ']' . $post_type . '[/zrl]'; + + $arr['body'] = sprintf( $bodyverb, $alink, $ulink, $plink ); + + $arr['verb'] = $activity; + $arr['obj_type'] = $objtype; + $arr['object'] = $obj; + + $arr['allow_cid'] = $item['allow_cid']; + $arr['allow_gid'] = $item['allow_gid']; + $arr['deny_cid'] = $item['deny_cid']; + $arr['deny_gid'] = $item['deny_gid']; + + + $post = item_store($arr); + $post_id = $post['item_id']; + + $arr['id'] = $post_id; + + call_hooks('post_local_end', $arr); + + killme(); + + + + + + + + + + + + + + + + + + + + - if(! $owner) { - logger('like: no owner'); - return; - } - if(! $remote_owner) - $remote_owner = $owner; - // This represents the person posting - if((local_user()) && (local_user() == $owner_uid)) { - $contact = $owner; - } - else { - $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($_SESSION['visitor_id']), - intval($owner_uid) - ); - if(count($r)) - $contact = $r[0]; - } - if(! $contact) { - return; - } - $uri = item_message_id(); $post_type = (($item['resource_id']) ? t('photo') : t('status')); $objtype = (($item['resource_id']) ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE ); + $link = xmlify('<link rel="alternate" type="text/html" href="' . $a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id'] . '" />' . "\n") ; $body = $item['body']; @@ -96,20 +182,16 @@ function subthread_content(&$a) { <object> <type>$objtype</type> <local>1</local> - <id>{$item['uri']}</id> + <id>{$item['mid']}</id> <link>$link</link> <title></title> <content>$body</content> </object> EOT; - $bodyverb = t('%1$s is following %2$s\'s %3$s'); - - if(! isset($bodyverb)) - return; $arr = array(); - $arr['uri'] = $uri; + $arr['mid'] = $mid; $arr['uid'] = $owner_uid; $arr['contact-id'] = $contact['id']; $arr['type'] = 'activity'; @@ -117,8 +199,8 @@ EOT; $arr['origin'] = 1; $arr['gravity'] = GRAVITY_LIKE; $arr['parent'] = $item['id']; - $arr['parent-uri'] = $item['uri']; - $arr['thr_parent'] = $item['uri']; + $arr['parent-mid'] = $item['mid']; + $arr['thr_parent'] = $item['mid']; $arr['owner-name'] = $remote_owner['name']; $arr['owner-link'] = $remote_owner['url']; $arr['owner-avatar'] = $remote_owner['thumb']; @@ -126,9 +208,9 @@ EOT; $arr['author-link'] = $contact['url']; $arr['author-avatar'] = $contact['thumb']; - $ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]'; - $alink = '[url=' . $item['author-link'] . ']' . $item['author-name'] . '[/url]'; - $plink = '[url=' . $a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id'] . ']' . $post_type . '[/url]'; + $ulink = '[zrl=' . $contact['url'] . ']' . $contact['name'] . '[/zrl]'; + $alink = '[zrl=' . $item['author-link'] . ']' . $item['author-name'] . '[/zrl]'; + $plink = '[zrl=' . $a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id'] . ']' . $post_type . '[/zrl]'; $arr['body'] = sprintf( $bodyverb, $ulink, $alink, $plink ); $arr['verb'] = $activity; @@ -142,7 +224,8 @@ EOT; $arr['unseen'] = 1; $arr['last-child'] = 0; - $post_id = item_store($arr); + $post = item_store($arr); + $post_id = $post['item_id']; if(! $item['visible']) { $r = q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d AND `uid` = %d LIMIT 1", diff --git a/mod/suggest.php b/mod/suggest.php index 4aed2e61a..8a6b50b22 100644 --- a/mod/suggest.php +++ b/mod/suggest.php @@ -2,25 +2,23 @@ require_once('include/socgraph.php'); require_once('include/contact_widgets.php'); +require_once('include/widgets.php'); function suggest_init(&$a) { if(! local_user()) return; - if(x($_GET,'ignore') && intval($_GET['ignore'])) { - q("insert into gcign ( uid, gcid ) values ( %d, %d ) ", + if(x($_GET,'ignore')) { + q("insert into xign ( uid, xchan ) values ( %d, '%s' ) ", intval(local_user()), - intval($_GET['ignore']) + dbesc($_GET['ignore']) ); } } - - - function suggest_content(&$a) { $o = ''; @@ -31,38 +29,37 @@ function suggest_content(&$a) { $_SESSION['return_url'] = $a->get_baseurl() . '/' . $a->cmd; - $a->page['aside'] .= follow_widget(); - $a->page['aside'] .= findpeople_widget(); - - - $o .= '<h2>' . t('Friend Suggestions') . '</h2>'; - + $r = suggestion_query(local_user(),get_observer_hash()); - $r = suggestion_query(local_user()); - - if(! count($r)) { - $o .= t('No suggestions available. If this is a new site, please try again in 24 hours.'); - return $o; + if(! $r) { + info( t('No suggestions available. If this is a new site, please try again in 24 hours.')); + return; } - $tpl = get_markup_template('suggest_friends.tpl'); + $arr = array(); foreach($r as $rr) { - $connlnk = $a->get_baseurl() . '/follow/?url=' . (($rr['connect']) ? $rr['connect'] : $rr['url']); - - $o .= replace_macros($tpl,array( - '$url' => zid($rr['url']), - '$name' => $rr['name'], - '$photo' => $rr['photo'], - '$ignlnk' => $a->get_baseurl() . '/suggest?ignore=' . $rr['id'], - '$conntxt' => t('Connect'), - '$connlnk' => $connlnk, - '$ignore' => t('Ignore/Hide') - )); + $connlnk = $a->get_baseurl() . '/follow/?url=' . $rr['xchan_addr']; + + $arr[] = array( + 'url' => chanlink_url($rr['xchan_url']), + 'profile' => $rr['xchan_url'], + 'name' => $rr['xchan_name'], + 'photo' => $rr['xchan_photo_m'], + 'ignlnk' => $a->get_baseurl() . '/suggest?ignore=' . $rr['xchan_hash'], + 'conntxt' => t('Connect'), + 'connlnk' => $connlnk, + 'ignore' => t('Ignore/Hide') + ); } - $o .= cleardiv(); -// $o .= paginate($a); + + $o = replace_macros(get_markup_template('suggest_page.tpl'),array( + '$title' => t('Channel Suggestions'), + '$entries' => $arr + )); + return $o; + } diff --git a/mod/tagger.php b/mod/tagger.php index 9c36a8b09..3d8043f68 100644 --- a/mod/tagger.php +++ b/mod/tagger.php @@ -11,6 +11,8 @@ function tagger_content(&$a) { return; } + $observer_hash = get_observer_hash(); + $term = notags(trim($_GET['term'])); // no commas allowed $term = str_replace(array(',',' '),array('','_'),$term); @@ -23,11 +25,12 @@ function tagger_content(&$a) { logger('tagger: tag ' . $term . ' item ' . $item_id); - $r = q("SELECT * FROM `item` WHERE `id` = '%s' LIMIT 1", - dbesc($item_id) + $r = q("SELECT * FROM item left join xchan on xchan_hash = author_xchan WHERE id = '%s' and uid = %d LIMIT 1", + dbesc($item_id), + intval(local_user()) ); - if(! $item_id || (! count($r))) { + if((! $item_id) || (! $r)) { logger('tagger: no item ' . $item_id); return; } @@ -36,89 +39,85 @@ function tagger_content(&$a) { $owner_uid = $item['uid']; - $r = q("select `nickname`,`blocktags` from user where uid = %d limit 1", - intval($owner_uid) - ); - if(count($r)) { - $owner_nick = $r[0]['nickname']; - $blocktags = $r[0]['blocktags']; + switch($item['resource_type']) { + case 'photo': + $targettype = ACTIVITY_OBJ_PHOTO; + $post_type = t('photo'); + break; + case 'event': + $targgettype = ACTIVITY_OBJ_EVENT; + $post_type = t('event'); + break; + default: + $targettype = ACTIVITY_OBJ_NOTE; + $post_type = t('status'); + if($item['mid'] != $item['parent_mid']) + $post_type = t('comment'); + break; } - if(local_user() != $owner_uid) - return; - $r = q("select * from contact where self = 1 and uid = %d limit 1", - intval(local_user()) - ); - if(count($r)) - $contact = $r[0]; - else { - logger('tagger: no contact_id'); - return; - } + $links = array(array('rel' => 'alternate','type' => 'text/html', + 'href' => z_root() . '/display/' . $item['mid'])); - $uri = item_message_id(); - $xterm = xmlify($term); - $post_type = (($item['resource_id']) ? t('photo') : t('status')); - $targettype = (($item['resource_id']) ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE ); + $target = json_encode(array( + 'type' => $targettype, + 'id' => $item['mid'], + 'link' => $links, + 'title' => $item['title'], + 'content' => $item['body'], + 'created' => $item['created'], + 'edited' => $item['edited'], + 'author' => array( + 'name' => $item['xchan_name'], + 'address' => $item['xchan_addr'], + 'guid' => $item['xchan_guid'], + 'guid_sig' => $item['xchan_guid_sig'], + 'link' => array( + array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item['xchan_url']), + array('rel' => 'photo', 'type' => $item['xchan_photo_mimetype'], 'href' => $item['xchan_photo_m'])), + ), + )); - $link = xmlify('<link rel="alternate" type="text/html" href="' - . $a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id'] . '" />' . "\n") ; - $body = xmlify($item['body']); - $target = <<< EOT - <target> - <type>$targettype</type> - <local>1</local> - <id>{$item['uri']}</id> - <link>$link</link> - <title></title> - <content>$body</content> - </target> -EOT; + $link = xmlify('<link rel="alternate" type="text/html" href="' + . $a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id'] . '" />' . "\n") ; $tagid = $a->get_baseurl() . '/search?tag=' . $term; $objtype = ACTIVITY_OBJ_TAGTERM; - $obj = <<< EOT - <object> - <type>$objtype</type> - <local>1</local> - <id>$tagid</id> - <link>$tagid</link> - <title>$xterm</title> - <content>$xterm</content> - </object> -EOT; + $obj = json_encode(array( + 'type' => $objtype, + 'id' => $tagid, + 'link' => array(array('rel' => 'alternate','type' => 'text/html', 'href' => $tagid)), + 'title' => $term, + 'content' => $term + )); $bodyverb = t('%1$s tagged %2$s\'s %3$s with %4$s'); - if(! isset($bodyverb)) - return; + // saving here for reference + // also check out x22d5 and x0d6b and x0db8 and x24d0 and xff20 !!! + + $termlink = html_entity_decode('⌗') . '[zrl=' . $a->get_baseurl() . '/search?tag=' . urlencode($term) . ']'. $term . '[/zrl]'; - $termlink = html_entity_decode('⌗') . '[url=' . $a->get_baseurl() . '/search?tag=' . urlencode($term) . ']'. $term . '[/url]'; + $channel = $a->get_channel(); $arr = array(); - $arr['uri'] = $uri; - $arr['uid'] = $owner_uid; - $arr['contact-id'] = $contact['id']; - $arr['type'] = 'activity'; - $arr['wall'] = $item['wall']; - $arr['gravity'] = GRAVITY_COMMENT; - $arr['parent'] = $item['id']; - $arr['parent_uri'] = $item['uri']; - $arr['owner-name'] = $item['author-name']; - $arr['owner-link'] = $item['author-link']; - $arr['owner-avatar'] = $item['author-avatar']; - $arr['author-name'] = $contact['name']; - $arr['author-link'] = $contact['url']; - $arr['author-avatar'] = $contact['thumb']; + $arr['owner_xchan'] = $item['owner_xchan']; + $arr['author_xchan'] = $channel['channel_hash']; + + + $arr['item_flags'] = ITEM_ORIGIN; + if($item['item_flags'] & ITEM_WALL) + $arr['item_flags'] |= ITEM_WALL; - $ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]'; - $alink = '[url=' . $item['author-link'] . ']' . $item['author-name'] . '[/url]'; - $plink = '[url=' . $item['plink'] . ']' . $post_type . '[/url]'; + $ulink = '[zrl=' . $channel['xchan_url'] . ']' . $channel['channel_name'] . '[/zrl]'; + $alink = '[zrl=' . $item['xchan_url'] . ']' . $item['xchan_name'] . '[/zrl]'; + $plink = '[zrl=' . $item['plink'] . ']' . $post_type . '[/zrl]'; + $arr['body'] = sprintf( $bodyverb, $ulink, $alink, $plink, $termlink ); $arr['verb'] = ACTIVITY_TAG; @@ -126,65 +125,14 @@ EOT; $arr['target'] = $target; $arr['obj_type'] = $objtype; $arr['object'] = $obj; - $arr['private'] = $item['private']; - $arr['allow_cid'] = $item['allow_cid']; - $arr['allow_gid'] = $item['allow_gid']; - $arr['deny_cid'] = $item['deny_cid']; - $arr['deny_gid'] = $item['deny_gid']; - $arr['visible'] = 1; - $arr['unseen'] = 1; - $arr['origin'] = 1; - - $post_id = item_store($arr); - - q("UPDATE `item` set plink = '%s' where id = %d limit 1", - dbesc($a->get_baseurl() . '/display/' . $owner_nick . '/' . $post_id), - intval($post_id) - ); - - - if(! $item['visible']) { - $r = q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($item['id']), - intval($owner_uid) - ); - } - - if((! $blocktags) && (! stristr($item['tag'], ']' . $term . '[' ))) { - q("update item set tag = '%s' where id = %d limit 1", - dbesc($item['tag'] . (strlen($item['tag']) ? ',' : '') . '#[url=' . $a->get_baseurl() . '/search?tag=' . $term . ']'. $term . '[/url]'), - intval($item['id']) - ); - } - - // if the original post is on this site, update it. - - $r = q("select `tag`,`id`,`uid` from item where `origin` = 1 AND `uri` = '%s' LIMIT 1", - dbesc($item['uri']) - ); - if(count($r)) { - $x = q("SELECT `blocktags` FROM `user` WHERE `uid` = %d limit 1", - intval($r[0]['uid']) - ); - if(count($x) && !$x[0]['blocktags'] && (! stristr($r[0]['tag'], ']' . $term . '['))) { - q("update item set tag = '%s' where id = %d limit 1", - dbesc($r[0]['tag'] . (strlen($r[0]['tag']) ? ',' : '') . '#[url=' . $a->get_baseurl() . '/search?tag=' . $term . ']'. $term . '[/url]'), - intval($r[0]['id']) - ); - } - - } - - - $arr['id'] = $post_id; - - call_hooks('post_local_end', $arr); + $arr['parent_mid'] = $item['mid']; + + store_item_tag($item['uid'],$item['id'],TERM_OBJ_POST,TERM_HASHTAG,$term,$tagid); + $ret = post_activity_item($arr); - proc_run('php',"include/notifier.php","tag","$post_id"); + if($ret['success']) + proc_run('php','include/notifier.php','tag',$ret['activity']['id']); killme(); - return; // NOTREACHED - - }
\ No newline at end of file diff --git a/mod/thing.php b/mod/thing.php new file mode 100644 index 000000000..b6d59a3ee --- /dev/null +++ b/mod/thing.php @@ -0,0 +1,335 @@ +<?php /** @file */ + +require_once('include/items.php'); +require_once('include/contact_selectors.php'); + + +function thing_init(&$a) { + + if(! local_user()) + return; + + + + + $account_id = $a->get_account(); + $channel = $a->get_channel(); + + $term_hash = (($_REQUEST['term_hash']) ? $_REQUEST['term_hash'] : ''); + + $name = escape_tags($_REQUEST['term']); + $verb = escape_tags($_REQUEST['verb']); + $activity = intval($_REQUEST['activity']); + $profile_guid = escape_tags($_REQUEST['profile_assign']); + $url = $_REQUEST['link']; + $photo = $_REQUEST['img']; + + $hash = random_string(); + + + $verbs = obj_verbs(); + + /** + * verbs: [0] = first person singular, e.g. "I want", [1] = 3rd person singular, e.g. "Bill wants" + * We use the first person form when creating an activity, but the third person for use in activities + * FIXME: There is no accounting for verb gender for languages where this is significant. We may eventually + * require obj_verbs() to provide full conjugations and specify which form to use in the $_REQUEST params to this module. + */ + + $translated_verb = $verbs[$verb][1]; + + /** + * The site administrator can do things that normals cannot. + * This is restricted because it will likely cause + * an activitystreams protocol violation and the activity might + * choke in some other network and result in unnecessary + * support requests. It isn't because we're trying to be heavy-handed + * about what you can and can't do. + */ + + if(! $translated_verb) { + if(is_site_admin()) + $translated_verb = $verb; + } + + /** + * Things, objects: We do not provide definite (a, an) or indefinite (the) articles or singular/plural designators + * That needs to be specified in your thing. e.g. Mike has "a carrot", Greg wants "balls", Bob likes "the Boston Red Sox". + */ + + /** + * Future work on this module might produce more complex activities with targets, e.g. Phillip likes Karen's moustache + * and to describe other non-thing objects like channels, such as Karl wants Susan - where Susan represents a channel profile. + */ + + if((! $name) || (! $translated_verb)) + return; + + + + + + if($term_hash) { + $t = q("select * from obj left join term on obj_obj = term_hash where term_hash != '' and obj_type = %d and term_hash = '%s' limit 1", + intval(TERM_OBJ_THING), + dbesc($term_hash) + ); + if(! $t) { + notice( t('Item not found.') . EOL); + return; + } + $orig_record = $t[0]; + if($photo != $orig_record['imgurl']) { + $arr = import_profile_photo($photo,get_observer_hash(),true); + $local_photo = $arr[0]; + $local_photo_type = $arr[3]; + } + else + $local_photo = $orig_record['imgurl']; + + $r = q("update term set term = '%s', url = '%s', imgurl = '%s' where term_hash = '%s' and uid = %d limit 1", + dbesc($name), + dbesc(($url) ? $url : z_root() . '/thing/' . $term_hash), + dbesc($local_photo), + dbesc($term_hash), + intval(local_user()) + ); + + info( t('Thing updated') . EOL); + return; + } + + $sql = (($profile_guid) ? " and profile_guid = '" . dbesc($profile_guid) . "' " : " and is_default = 1 "); + $p = q("select profile_guid, is_default from profile where uid = %d $sql limit 1", + intval(local_user()) + ); + + if($p) + $profile = $p[0]; + else + return; + + $local_photo = null; + + if($photo) { + $arr = import_profile_photo($photo,get_observer_hash(),true); + $local_photo = $arr[0]; + $local_photo_type = $arr[3]; + } + + + $r = q("select * from term where uid = %d and otype = %d and type = %d and term = '%s' limit 1", + intval(local_user()), + intval(TERM_OBJ_THING), + intval(TERM_THING), + dbesc($name) + ); + if(! $r) { + $r = q("insert into term ( aid, uid, oid, otype, type, term, url, imgurl, term_hash ) + values( %d, %d, %d, %d, %d, '%s', '%s', '%s', '%s' ) ", + intval($account_id), + intval(local_user()), + 0, + intval(TERM_OBJ_THING), + intval(TERM_THING), + dbesc($name), + dbesc(($url) ? $url : z_root() . '/thing/' . $hash), + dbesc(($photo) ? $local_photo : ''), + dbesc($hash) + ); + $r = q("select * from term where uid = %d and otype = %d and type = %d and term = '%s' limit 1", + intval(local_user()), + intval(TERM_OBJ_THING), + intval(TERM_THING), + dbesc($name) + ); + } + $term = $r[0]; + + $r = q("insert into obj ( obj_page, obj_verb, obj_type, obj_channel, obj_obj) values ('%s','%s', %d, %d, '%s') ", + dbesc($profile['profile_guid']), + dbesc($verb), + intval(TERM_OBJ_THING), + intval(local_user()), + dbesc($term['term_hash']) + ); + + if(! $r) { + notice( t('Object store: failed')); + return; + } + + info( t('Thing added')); + + + if($activity) { + $arr = array(); + $links = array(array('rel' => 'alternate','type' => 'text/html', 'href' => $term['url'])); + if($local_photo) + $links[] = array('rel' => 'photo', 'type' => $local_photo_type, 'href' => $local_photo); + + + $objtype = ACTIVITY_OBJ_THING; + + $obj = json_encode(array( + 'type' => $objtype, + 'id' => $term['url'], + 'link' => $links, + 'title' => $term['term'], + 'content' => $term['term'] + )); + + $bodyverb = str_replace('OBJ: ', '',t('OBJ: %1$s %2$s %3$s')); + + $arr['owner_xchan'] = $channel['channel_hash']; + $arr['author_xchan'] = $channel['channel_hash']; + + + $arr['item_flags'] = ITEM_ORIGIN|ITEM_WALL|ITEM_THREAD_TOP; + + $ulink = '[zrl=' . $channel['xchan_url'] . ']' . $channel['channel_name'] . '[/zrl]'; + $plink = '[zrl=' . $term['url'] . ']' . $term['term'] . '[/zrl]'; + + $arr['body'] = sprintf( $bodyverb, $ulink, $translated_verb, $plink ); + + if($local_photo) + $arr['body'] .= "\n\n[zmg]" . $local_photo . "[/zmg]"; + + $arr['verb'] = $verb; + $arr['obj_type'] = $objtype; + $arr['object'] = $obj; + + if(! $profile['is_default']) { + $arr['item_private'] = true; + $str = ''; + $r = q("select abook_xchan from abook where abook_channel = %d and abook_profile = '%s'", + intval(local_user()), + dbesc($profile_guid) + ); + if($r) { + $arr['allow_cid'] = ''; + foreach($r as $rr) + $arr['allow_cid'] .= '<' . $rr['abook_xchan'] . '>'; + } + else + $arr['allow_cid'] = '<' . get_observer_hash() . '>'; + } + + $ret = post_activity_item($arr); + } +} + + +function thing_content(&$a) { + + if(argc() == 2) { + + $r = q("select * from obj left join term on obj_obj = term_hash where term_hash != '' and obj_type = %d and term_hash = '%s' limit 1", + intval(TERM_OBJ_THING), + dbesc(argv(1)) + ); + + if($r) { + return replace_macros(get_markup_template('show_thing.tpl'), array( + '$header' => t('Show Thing'), + '$edit' => t('Edit'), + '$delete' => t('Delete'), + '$canedit' => ((local_user() && local_user() == $r[0]['obj_channel']) ? true : false), + '$thing' => $r[0] )); + } + else { + notice( t('item not found.') . EOL); + return; + } + } + + $channel = $a->get_channel(); + + if(! (local_user() && $channel)) { + notice( t('Permission denied.') . EOL); + return; + } + + $thing_hash = ''; + + + if(argc() == 3 && argv(1) === 'edit') { + $thing_hash = argv(2); + + + $r = q("select * from obj left join term on obj_obj = term_hash where term_hash != '' and obj_type = %d and term_hash = '%s' limit 1", + intval(TERM_OBJ_THING), + dbesc($thing_hash) + ); + + if((! $r) || ($r[0]['obj_channel'] != local_user())) { + notice( t('Permission denied.') . EOL); + return ''; + } + + + $o .= replace_macros(get_markup_template('thing_edit.tpl'),array( + '$thing_hdr' => t('Edit Thing'), + '$multiprof' => feature_enabled(local_user(),'multi_profiles'), + '$profile_lbl' => t('Select a profile'), + '$profile_select' => contact_profile_assign($r[0]['obj_page']), + '$verb_lbl' => $channel['channel_name'], + '$verb_select' => obj_verb_selector($r[0]['obj_verb']), + '$activity' => array('activity',t('Post an activity'),true,t('Only sends to viewers of the applicable profile')), + '$thing_hash' => $thing_hash, + '$thing_lbl' => t('Name of thing e.g. something'), + '$thething' => $r[0]['term'], + '$url_lbl' => t('URL of thing (optional)'), + '$theurl' => $r[0]['url'], + '$img_lbl' => t('URL for photo of thing (optional)'), + '$imgurl' => $r[0]['imgurl'], + '$submit' => t('Submit') + )); + + return $o; + } + + if(argc() == 3 && argv(1) === 'drop') { + $thing_hash = argv(2); + + $r = q("select * from obj left join term on obj_obj = term_hash where term_hash != '' and obj_type = %d and term_hash = '%s' limit 1", + intval(TERM_OBJ_THING), + dbesc($thing_hash) + ); + + if((! $r) || ($r[0]['obj_channel'] != local_user())) { + notice( t('Permission denied.') . EOL); + return ''; + } + + + $x = q("delete from obj where obj_obj = '%s' and obj_type = %d and obj_channel = %d limit 1", + dbesc($thing_hash), + intval(TERM_OBJ_THING), + intval(local_user()) + ); + $x = q("delete from term where term_hash = '%s' and uid = %d limit 1", + dbesc($thing_hash), + intval(local_user()) + ); + return $o; + } + + $o .= replace_macros(get_markup_template('thing_input.tpl'),array( + '$thing_hdr' => t('Add Thing to your Profile'), + '$multiprof' => feature_enabled(local_user(),'multi_profiles'), + '$profile_lbl' => t('Select a profile'), + '$profile_select' => contact_profile_assign(''), + '$verb_lbl' => $channel['channel_name'], + '$activity' => array('activity',t('Post an activity'),true,t('Only sends to viewers of the applicable profile')), + '$verb_select' => obj_verb_selector(), + '$thing_lbl' => t('Name of thing e.g. something'), + '$url_lbl' => t('URL of thing (optional)'), + '$img_lbl' => t('URL for photo of thing (optional)'), + '$submit' => t('Submit') + )); + + return $o; + + +} diff --git a/mod/toggle_mobile.php b/mod/toggle_mobile.php index 00991e44c..06dadca04 100644 --- a/mod/toggle_mobile.php +++ b/mod/toggle_mobile.php @@ -3,9 +3,9 @@ function toggle_mobile_init(&$a) { if(isset($_GET['off'])) - $_SESSION['show-mobile'] = false; + $_SESSION['show_mobile'] = false; else - $_SESSION['show-mobile'] = true; + $_SESSION['show_mobile'] = true; if(isset($_GET['address'])) $address = $_GET['address']; diff --git a/mod/toggle_safesearch.php b/mod/toggle_safesearch.php new file mode 100644 index 000000000..3c800c4f3 --- /dev/null +++ b/mod/toggle_safesearch.php @@ -0,0 +1,25 @@ +<?php + +function toggle_safesearch_init(&$a) { + +$observer = get_observer_hash(); +if (! $observer) + return; + +if($observer) + $safe_mode = get_xconfig($observer,'directory','safe_mode'); +if ($safe_mode == '') + set_xconfig($observer,'directory','safe_mode', '0'); +elseif($safe_mode == '0') + set_xconfig($observer,'directory','safe_mode', '1'); +elseif($safe_mode == '1') + set_xconfig($observer,'directory','safe_mode', '0'); + +if(isset($_GET['address'])) + $address = $_GET['address']; +else + $address = z_root() . '/directory'; + + goaway($address); +} + diff --git a/mod/uexport.php b/mod/uexport.php index e1fb22855..f3a2ce67c 100644 --- a/mod/uexport.php +++ b/mod/uexport.php @@ -1,72 +1,25 @@ <?php function uexport_init(&$a) { - if(! local_user()) killme(); - $user = array(); - $r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", - local_user() - ); - if(count($r)) { - foreach($r as $rr) - foreach($rr as $k => $v) - $user[$k] = $v; - - } - $contact = array(); - $r = q("SELECT * FROM `contact` WHERE `uid` = %d ", - intval(local_user()) - ); - if(count($r)) { - foreach($r as $rr) - foreach($rr as $k => $v) - $contact[][$k] = $v; - - } - - $profile = array(); - $r = q("SELECT * FROM `profile` WHERE `uid` = %d ", - intval(local_user()) - ); - if(count($r)) { - foreach($r as $rr) - foreach($rr as $k => $v) - $profile[][$k] = $v; - } - - $output = array('user' => $user, 'contact' => $contact, 'profile' => $profile ); - - header("Content-type: application/json"); - echo json_encode($output); + $channel = $a->get_channel(); - $r = q("SELECT count(*) as `total` FROM `item` WHERE `uid` = %d ", - intval(local_user()) - ); - if(count($r)) - $total = $r[0]['total']; + require_once('include/identity.php'); - // chunk the output to avoid exhausting memory + header('content-type: application/octet_stream'); + header('content-disposition: attachment; filename="' . $channel['channel_address'] . '.json"' ); - for($x = 0; $x < $total; $x += 500) { - $item = array(); - $r = q("SELECT * FROM `item` WHERE `uid` = %d LIMIT %d, %d", - intval(local_user()), - intval($x), - intval(500) - ); - if(count($r)) { - foreach($r as $rr) - foreach($rr as $k => $v) - $item[][$k] = $v; - } - $output = array('item' => $item); - echo json_encode($output); + if(argc() > 1 && argv(1) === 'basic') { + echo json_encode(identity_basic_export(local_user())); + killme(); } - - killme(); - + if(argc() > 1 && argv(1) === 'complete') { + echo json_encode('not yet implemented'); + killme(); + } + }
\ No newline at end of file diff --git a/mod/update_channel.php b/mod/update_channel.php index 19226297b..bdde0a3be 100644 --- a/mod/update_channel.php +++ b/mod/update_channel.php @@ -39,15 +39,17 @@ function update_channel_content(&$a) { $replace = "<img\${1} dst=\"\${2}\""; $text = preg_replace($pattern, $replace, $text); - $replace = '<br />' . t('[Embedded content - reload page to view]') . '<br />'; - $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i"; - $text = preg_replace($pattern, $replace, $text); + if(! $load) { + $replace = '<br />' . t('[Embedded content - reload page to view]') . '<br />'; + $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i"; + $text = preg_replace($pattern, $replace, $text); + } /** * reportedly some versions of MSIE don't handle tabs in XMLHttpRequest documents very well diff --git a/mod/update_community.php b/mod/update_display.php index 3dcbce6b1..5802852bb 100644 --- a/mod/update_community.php +++ b/mod/update_display.php @@ -2,19 +2,26 @@ // See update_profile.php for documentation -require_once('mod/community.php'); +require_once('mod/display.php'); +require_once('include/group.php'); -function update_community_content(&$a) { +function update_display_content(&$a) { + $profile_uid = intval($_GET['p']); + if(! $profile_uid) + $profile_uid = (-1); + $load = (((argc() > 1) && (argv(1) == 'load')) ? 1 : 0); header("Content-type: text/html"); echo "<!DOCTYPE html><html><body>\r\n"; echo (($_GET['msie'] == 1) ? '<div>' : '<section>'); - $text = community_content($a,true); - $pattern = "/<img([^>]*) src=\"([^\"]*)\"/"; - $replace = "<img\${1} dst=\"\${2}\""; - $text = preg_replace($pattern, $replace, $text); + $text = display_content($a,$profile_uid, $load); + $pattern = "/<img([^>]*) src=\"([^\"]*)\"/"; + $replace = "<img\${1} dst=\"\${2}\""; + $text = preg_replace($pattern, $replace, $text); + + if(! $load) { $replace = '<br />' . t('[Embedded content - reload page to view]') . '<br />'; $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i"; $text = preg_replace($pattern, $replace, $text); @@ -24,10 +31,12 @@ function update_community_content(&$a) { $text = preg_replace($pattern, $replace, $text); $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i"; $text = preg_replace($pattern, $replace, $text); + } - echo str_replace("\t",' ',$text); + echo str_replace("\t",' ',$text); echo (($_GET['msie'] == 1) ? '</div>' : '</section>'); echo "</body></html>\r\n"; +// logger('update_display: ' . $text); killme(); }
\ No newline at end of file diff --git a/mod/update_network.php b/mod/update_network.php index e13eef0e6..0021af876 100644 --- a/mod/update_network.php +++ b/mod/update_network.php @@ -11,7 +11,7 @@ function update_network_content(&$a) { $load = (((argc() > 1) && (argv(1) == 'load')) ? 1 : 0); header("Content-type: text/html"); echo "<!DOCTYPE html><html><body>\r\n"; - echo (($_GET['msie'] == 1) ? '<div>' : '<section>'); + echo ((array_key_exists('msie',$_GET) && $_GET['msie'] == 1) ? '<div>' : '<section>'); $text = network_content($a,$profile_uid, $load); @@ -19,20 +19,22 @@ function update_network_content(&$a) { $replace = "<img\${1} dst=\"\${2}\""; $text = preg_replace($pattern, $replace, $text); - $replace = '<br />' . t('[Embedded content - reload page to view]') . '<br />'; - $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i"; - $text = preg_replace($pattern, $replace, $text); - + if(! $load) { + $replace = '<br />' . t('[Embedded content - reload page to view]') . '<br />'; + $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i"; + $text = preg_replace($pattern, $replace, $text); + } echo str_replace("\t",' ',$text); - echo (($_GET['msie'] == 1) ? '</div>' : '</section>'); + echo ((array_key_exists('msie',$_GET) && $_GET['msie'] == 1) ? '</div>' : '</section>'); echo "</body></html>\r\n"; +// logger('update_network: ' . $text); killme(); }
\ No newline at end of file diff --git a/mod/update_search.php b/mod/update_search.php new file mode 100644 index 000000000..ec7599b79 --- /dev/null +++ b/mod/update_search.php @@ -0,0 +1,66 @@ +<?php + +/** + * Module: update_profile + * Purpose: AJAX synchronisation of search page + * + */ + + +require_once('mod/search.php'); + +function update_search_content(&$a) { + + $profile_uid = intval($_GET['p']); + if(! $profile_uid) + $profile_uid = (-1); + + $load = (((argc() > 1) && (argv(1) == 'load')) ? 1 : 0); + + header("Content-type: text/html"); + echo "<!DOCTYPE html><html><body>\r\n"; + + /** + * We can remove this hack once Internet Explorer recognises HTML5 natively + */ + + echo (($_GET['msie'] == 1) ? '<div>' : '<section>'); + + /** + * + * Grab the page inner contents by calling the content function from the profile module directly, + * but move any image src attributes to another attribute name. This is because + * some browsers will prefetch all the images for the page even if we don't need them. + * The only ones we need to fetch are those for new page additions, which we'll discover + * on the client side and then swap the image back. + * + */ + + $text = search_content($a,$profile_uid,$load); + + $pattern = "/<img([^>]*) src=\"([^\"]*)\"/"; + $replace = "<img\${1} dst=\"\${2}\""; + $text = preg_replace($pattern, $replace, $text); + + if(! $load) { + $replace = '<br />' . t('[Embedded content - reload page to view]') . '<br />'; + $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i"; + $text = preg_replace($pattern, $replace, $text); + } + + /** + * reportedly some versions of MSIE don't handle tabs in XMLHttpRequest documents very well + */ + + echo str_replace("\t",' ',$text); + echo (($_GET['msie'] == 1) ? '</div>' : '</section>'); + echo "</body></html>\r\n"; + killme(); + +}
\ No newline at end of file diff --git a/mod/view.php b/mod/view.php index 965e18067..d4381743c 100644 --- a/mod/view.php +++ b/mod/view.php @@ -1,17 +1,15 @@ <?php /** - * load view/theme/$current_theme/style.php with friendica contex + * load view/theme/$current_theme/style.php with Red context */ function view_init($a){ + header("Content-Type: text/css"); - if ($a->argc == 4){ - $theme = $a->argv[2]; - $THEMEPATH = "view/theme/$theme"; - if(file_exists("view/theme/$theme/php/style.php")) - require_once("view/theme/$theme/php/style.php"); - } - + $theme = argv(2); + $THEMEPATH = "view/theme/$theme"; + if(file_exists("view/theme/$theme/php/style.php")) + require_once("view/theme/$theme/php/style.php"); killme(); } diff --git a/mod/viewconnections.php b/mod/viewconnections.php new file mode 100644 index 000000000..b6a6b483c --- /dev/null +++ b/mod/viewconnections.php @@ -0,0 +1,92 @@ +<?php +require_once('include/contact_selectors.php'); +require_once('include/Contact.php'); + +function viewconnections_init(&$a) { + + if((get_config('system','block_public')) && (! local_user()) && (! remote_user())) { + return; + } + if(argc() > 1) + profile_load($a,argv(1)); +} + +function viewconnections_content(&$a) { + + if((get_config('system','block_public')) && (! local_user()) && (! remote_user())) { + notice( t('Public access denied.') . EOL); + return; + } + + if(((! count($a->profile)) || ($a->profile['hide_friends']))) { + notice( t('Permission denied.') . EOL); + return; + } + + if(! perm_is_allowed($a->profile['uid'], get_observer_hash(),'view_contacts')) { + notice( t('Permission denied.') . EOL); + return; + } + + $is_owner = ((local_user() && local_user() == $a->profile['uid']) ? true : false); + + $abook_flags = ABOOK_FLAG_PENDING|ABOOK_FLAG_SELF; + $xchan_flags = XCHAN_FLAGS_ORPHAN|XCHAN_FLAGS_DELETED; + if(! $is_owner) { + $abook_flags = $abook_flags | ABOOK_FLAGS_HIDDEN; + $xchan_flags = $xchan_flags | XCHAN_FLAGS_HIDDEN; + } + + $r = q("SELECT count(*) as total FROM abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and not (abook_flags & %d ) and not ( xchan_flags & %d ) ", + intval($a->profile['uid']), + intval($abook_flags), + intval($xchan_flags) + ); + if($r) { + $a->set_pager_total($r[0]['total']); + } + + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and not ( abook_flags & %d ) and not ( xchan_flags & %d ) order by xchan_name LIMIT %d , %d ", + intval($a->profile['uid']), + intval($abook_flags), + intval($xchan_flags), + intval($a->pager['start']), + intval($a->pager['itemspage']) + ); + + if(! $r) { + info( t('No connections.') . EOL ); + return $o; + } + + $contacts = array(); + + foreach($r as $rr) { + + $url = chanlink_url($rr['xchan_url']); + if($url) { + $contacts[] = array( + 'id' => $rr['abook_id'], + 'img_hover' => sprintf( t('Visit %s\'s profile [%s]'), $rr['xchan_name'], $rr['xchan_url']), + 'thumb' => $rr['xchan_photo_m'], + 'name' => substr($rr['xchan_name'],0,20), + 'username' => $rr['xchan_addr'], + 'link' => $url, + 'sparkle' => '', + 'itemurl' => $rr['url'], + 'network' => '', + ); + } + } + + + $tpl = get_markup_template("viewcontact_template.tpl"); + $o .= replace_macros($tpl, array( + '$title' => t('View Connnections'), + '$contacts' => $contacts, + '$paginate' => paginate($a), + )); + + + return $o; +} diff --git a/mod/viewcontacts.php b/mod/viewcontacts.php deleted file mode 100644 index 8133fb4a0..000000000 --- a/mod/viewcontacts.php +++ /dev/null @@ -1,83 +0,0 @@ -<?php -require_once('include/contact_selectors.php'); - -function viewcontacts_init(&$a) { - - if((get_config('system','block_public')) && (! local_user()) && (! remote_user())) { - return; - } - - profile_load($a,$a->argv[1]); -} - - -function viewcontacts_content(&$a) { - - if((get_config('system','block_public')) && (! local_user()) && (! remote_user())) { - notice( t('Public access denied.') . EOL); - return; - } - - if(((! count($a->profile)) || ($a->profile['hide_friends']))) { - notice( t('Permission denied.') . EOL); - return; - } - - - $r = q("SELECT COUNT(*) as `total` FROM `contact` WHERE `uid` = %d AND `blocked` = 0 AND `pending` = 0 AND `hidden` = 0 AND `archive` = 0 ", - intval($a->profile['uid']) - ); - if(count($r)) - $a->set_pager_total($r[0]['total']); - - $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `blocked` = 0 AND `pending` = 0 AND `hidden` = 0 AND `archive` = 0 ORDER BY `name` ASC LIMIT %d , %d ", - intval($a->profile['uid']), - intval($a->pager['start']), - intval($a->pager['itemspage']) - ); - if(! count($r)) { - info( t('No contacts.') . EOL ); - return $o; - } - - $contacts = array(); - - foreach($r as $rr) { - if($rr['self']) - continue; - - $url = $rr['url']; - - // route DFRN profiles through the redirect - - $is_owner = ((local_user() && ($a->profile['profile_uid'] == local_user())) ? true : false); - - if($is_owner && ($rr['network'] === NETWORK_DFRN) && ($rr['rel'])) - $url = 'redir/' . $rr['id']; - else - $url = zid($url); - - $contacts[] = array( - 'id' => $rr['id'], - 'img_hover' => sprintf( t('Visit %s\'s profile [%s]'), $rr['name'], $rr['url']), - 'thumb' => $rr['thumb'], - 'name' => substr($rr['name'],0,20), - 'username' => $rr['name'], - 'url' => $url, - 'sparkle' => '', - 'itemurl' => $rr['url'], - 'network' => network_to_name($rr['network']), - ); - } - - - $tpl = get_markup_template("viewcontact_template.tpl"); - $o .= replace_macros($tpl, array( - '$title' => t('View Contacts'), - '$contacts' => $contacts, - '$paginate' => paginate($a), - )); - - - return $o; -} diff --git a/mod/wall_attach.php b/mod/wall_attach.php index 5d9331ed0..47c097416 100644 --- a/mod/wall_attach.php +++ b/mod/wall_attach.php @@ -1,142 +1,23 @@ <?php require_once('include/attach.php'); -require_once('include/datetime.php'); +require_once('include/identity.php'); function wall_attach_post(&$a) { - - // Figure out who owns the page and if they allow attachments - - if(argc() > 1) { - $nick = argv(1); - $r = q("SELECT channel.* from channel where channel_address = '%s' limit 1", - dbesc($nick) - ); - if(! ($r && count($r))) - return; - $channel = $r[0]; - - } + if(argc() > 1) + $channel = get_channel_by_nick(argv(1)); else - return; - - - $can_post = false; - - - $visitor = 0; - - $page_owner_uid = $channel['channel_id']; - - -// $page_owner_cid = $r[0]['id']; -// $page_owner_nick = $r[0]['nickname']; -// $community_page = (($r[0]['page-flags'] == PAGE_COMMUNITY) ? true : false); - - if((local_user()) && (local_user() == $page_owner_uid)) - $can_post = true; - -// FIXME for forum and guests -// else { -// if($community_page && remote_user()) { -// $cid = 0; -// if(is_array($_SESSION['remote'])) { -// foreach($_SESSION['remote'] as $v) { -// if($v['uid'] == $page_owner_uid) { -// $cid = $v['cid']; -// break; -// } -// } -// } -// if($cid) {// - -// $r = q("SELECT `uid` FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `id` = %d AND `uid` = %d LIMIT 1", -// intval($cid), -// intval($page_owner_uid) -// ); -// if(count($r)) { -// $can_post = true; -// $visitor = $cid; -// } -// } -// } -// } - - - if(! $can_post) { - notice( t('Permission denied.') . EOL ); - killme(); - } - - if(! x($_FILES,'userfile')) killme(); - $src = $_FILES['userfile']['tmp_name']; - $filename = basename($_FILES['userfile']['name']); - $filesize = intval($_FILES['userfile']['size']); + $r = attach_store($channel,get_observer_hash()); - $maxfilesize = get_config('system','maxfilesize'); - - if(($maxfilesize) && ($filesize > $maxfilesize)) { - notice( sprintf(t('File exceeds size limit of %d'), $maxfilesize) . EOL); - @unlink($src); - return; - } - - $r = q("select sum(octet_length(data)) as total from attach where uid = %d ", - intval($page_owner_uid) - ); - - $limit = service_class_fetch($page_owner_uid,'attach_upload_limit'); - - if(($limit !== false) && (($r[0]['total'] + strlen($imagedata)) > $limit)) { - echo upgrade_message(true) . EOL ; - @unlink($src); - killme(); - } - - - $filedata = @file_get_contents($src); - $mimetype = z_mime_content_type($filename); - $hash = random_string(); - $created = datetime_convert(); - $r = q("INSERT INTO `attach` ( `uid`, `hash`, `filename`, `filetype`, `filesize`, `data`, `created`, `edited`, `allow_cid`, `allow_gid`,`deny_cid`, `deny_gid` ) - VALUES ( %d, '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", - intval($page_owner_uid), - dbesc($hash), - dbesc($filename), - dbesc($mimetype), - intval($filesize), - dbesc($filedata), - dbesc($created), - dbesc($created), - dbesc('<' . $channel['channel_hash'] . '>'), - dbesc(''), - dbesc(''), - dbesc('') - ); - - @unlink($src); - - if(! $r) { - echo ( t('File upload failed.') . EOL); - killme(); - } - - $r = q("SELECT `hash` FROM `attach` WHERE `uid` = %d AND `created` = '%s' AND `hash` = '%s' LIMIT 1", - intval($page_owner_uid), - dbesc($created), - dbesc($hash) - ); - - if(! count($r)) { - echo ( t('File upload failed.') . EOL); + if(! $r['success']) { + notice( $r['message'] . EOL); killme(); } - echo "\n\n" . '[attachment]' . $r[0]['hash'] . '[/attachment]' . "\n"; - + echo "\n\n" . '[attachment]' . $r['data']['hash'] . ',' . $r['data']['revision'] . '[/attachment]' . "\n"; killme(); - // NOTREACHED + } diff --git a/mod/wall_upload.php b/mod/wall_upload.php index c695f9b3e..f83f4f7cf 100644 --- a/mod/wall_upload.php +++ b/mod/wall_upload.php @@ -1,168 +1,55 @@ <?php -require_once('Photo.php'); +require_once('include/photo/photo_driver.php'); +require_once('include/identity.php'); +require_once('include/photos.php'); -function wall_upload_post(&$a) { - if(argc() > 1) { - if(! x($_FILES,'media')) { - $nick = argv(1); - } - else { - $user_info = api_get_user($a); - $nick = $user_info['screen_name']; - } - $r = q("SELECT channel.* from channel where channel_address = '%s' limit 1", - dbesc($nick) - ); - if(! ($r && count($r))) - return; - $channel = $r[0]; - } - else - return; - - - $can_post = false; - $visitor = 0; - - $page_owner_uid = $r[0]['channel_id']; -// $default_cid = $r[0]['id']; - - $page_owner_nick = $r[0]['channel_address']; - -// $community_page = (($r[0]['page-flags'] == PAGE_COMMUNITY) ? true : false); - - if((local_user()) && (local_user() == $page_owner_uid)) - $can_post = true; - -// else { -// if($community_page && remote_user()) { -// $cid = 0; -// if(is_array($_SESSION['remote'])) { -// foreach($_SESSION['remote'] as $v) { -// if($v['uid'] == $page_owner_uid) { -// $cid = $v['cid']; -// break; -// } -// } -// } -// if($cid) { - -// $r = q("SELECT `uid` FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `id` = %d AND `uid` = %d LIMIT 1", -// intval($cid), -// intval($page_owner_uid) -// ); -// if(count($r)) { -// $can_post = true; -// $visitor = $cid; -// } -// } -// } -// } - - if(! $can_post) { - notice( t('Permission denied.') . EOL ); - killme(); - } - if(! x($_FILES,'userfile') && ! x($_FILES,'media')) - killme(); +function wall_upload_post(&$a) { - if(x($_FILES,'userfile')) { - $src = $_FILES['userfile']['tmp_name']; - $filename = basename($_FILES['userfile']['name']); - $filesize = intval($_FILES['userfile']['size']); - $filetype = $_FILES['userfile']['type']; - } - elseif(x($_FILES,'media')) { - $src = $_FILES['media']['tmp_name']; - $filename = basename($_FILES['media']['name']); - $filesize = intval($_FILES['media']['size']); - $filetype = $_FILES['media']['type']; - } - - if ($filetype=="") $filetype=guess_image_type($filename); - $maximagesize = get_config('system','maximagesize'); + $using_api = ((x($_FILES,'media')) ? true : false); - if(($maximagesize) && ($filesize > $maximagesize)) { - echo sprintf( t('Image exceeds size limit of %d'), $maximagesize) . EOL; - @unlink($src); - killme(); + if($using_api) { + require_once('include/api.php'); + $user_info = api_get_user($a); + $nick = $user_info['screen_name']; } - - $r = q("select sum(octet_length(data)) as total from photo where uid = %d and scale = 0 and album != 'Contact Photos' ", - intval($page_owner_uid) - ); - - $limit = service_class_fetch($page_owner_uid,'photo_upload_limit'); - - if(($limit !== false) && (($r[0]['total'] + strlen($imagedata)) > $limit)) { - echo upgrade_message(true) . EOL ; - @unlink($src); - killme(); + else { + if(argc() > 1) + $nick = argv(1); } + $channel = (($nick) ? get_channel_by_nick($nick) : false); - $imagedata = @file_get_contents($src); - $ph = new Photo($imagedata, $filetype); - - if(! $ph->is_valid()) { - echo ( t('Unable to process image.') . EOL); - @unlink($src); + if(! $channel) { + if($using_api) + return; + notice( t('Channel not found.') . EOL); killme(); } - $ph->orient($src); - @unlink($src); + $observer = $a->get_observer(); - $max_length = get_config('system','max_image_length'); - if(! $max_length) - $max_length = MAX_IMAGE_LENGTH; - if($max_length > 0) - $ph->scaleImage($max_length); + $args = array( 'source' => 'editor', 'album' => t('Wall Photos'), + 'not_visible' => 1, 'contact_allow' => array($channel['channel_hash'])); - $width = $ph->getWidth(); - $height = $ph->getHeight(); + $ret = photo_upload($channel,$observer,$args); - $hash = photo_new_resource(); - - $smallest = 0; - - $defperm = '<' . $channel['channel_hash'] . '>'; - - $r = $ph->store($page_owner_uid, $visitor, $hash, $filename, t('Wall Photos'), 0, 0, $defperm); - - if(! $r) { - echo ( t('Image upload failed.') . EOL); + if(! $ret['success']) { + if($using_api) + return; + notice($ret['message']); killme(); } - if($width > 640 || $height > 640) { - $ph->scaleImage(640); - $r = $ph->store($page_owner_uid, $visitor, $hash, $filename, t('Wall Photos'), 1, 0, $defperm); - if($r) - $smallest = 1; - } - - if($width > 320 || $height > 320) { - $ph->scaleImage(320); - $r = $ph->store($page_owner_uid, $visitor, $hash, $filename, t('Wall Photos'), 2, 0, $defperm); - if($r) - $smallest = 2; - } - - $basename = basename($filename); + $m = $ret['body']; - if($_REQUEST['silent']) { - $m = '[url=' . $a->get_baseurl() . '/photos/' . $page_owner_nick . '/image/' . $hash . '][img]' . $a->get_baseurl() . "/photo/{$hash}-{$smallest}.".$ph->getExt()."[/img][/url]"; - return($m); - } - else { - echo "\n\n" . '[url=' . $a->get_baseurl() . '/photos/' . $page_owner_nick . '/image/' . $hash . '][img]' . $a->get_baseurl() . "/photo/{$hash}-{$smallest}.".$ph->getExt()."[/img][/url]\n\n"; - } + if($using_api) + return("\n\n" . $ret['body'] . "\n\n"); + else + echo "\n\n" . $ret['body'] . "\n\n"; killme(); - // NOTREACHED } diff --git a/mod/webpages.php b/mod/webpages.php new file mode 100644 index 000000000..431caa628 --- /dev/null +++ b/mod/webpages.php @@ -0,0 +1,134 @@ +<?php + +function webpages_content(&$a) { + + if(argc() > 1) + $which = argv(1); + else { + notice( t('Requested profile is not available.') . EOL ); + $a->error = 404; + return; + } + + $profile = 0; + $channel = $a->get_channel(); + + if((local_user()) && (argc() > 2) && (argv(2) === 'view')) { + $which = $channel['channel_address']; + $profile = argv(1); + } + + profile_load($a,$which,$profile); + + + // Figure out who the page owner is. + $r = q("select channel_id from channel where channel_address = '%s'", + dbesc($which) + ); + if($r) { + $owner = intval($r[0]['channel_id']); + } + + // Get the observer, check their permissions + + $observer = $a->get_observer(); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + $perms = get_all_perms($owner,$ob_hash); + + if(! $perms['write_pages']) { + notice( t('Permission denied.') . EOL); + return; + } + +// if(local_user() && local_user() == $owner) { +// $a->set_widget('design',design_tools()); +// } + + + $mimetype = get_config('system','page_mimetype'); + if(! $mimetype) + $mimetype = 'choose'; + + $layout = get_config('system','page_layout'); + if(! $layout) + $layout = 'choose'; + + +// Create a status editor (for now - we'll need a WYSIWYG eventually) to create pages +// Nickname is set to the observers xchan, and profile_uid to the owners. This lets you post pages at other people's channels. + require_once ('include/conversation.php'); + require_once('include/acl_selectors.php'); + + + if(local_user() && local_user() == $a->profile_uid) { + $channel = $a->get_channel(); + $channel_acl = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + } + else + $channel_acl = array(); + + require_once('include/conversation.php'); + $o = profile_tabs($a,true); + + $o .= '<h2>' . t('Webpages') . '</h2>'; + + $x = array( + 'webpage' => ITEM_WEBPAGE, + 'is_owner' => true, + 'nickname' => $a->profile['channel_address'], + 'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), + 'bang' => (($group || $cid) ? '!' : ''), + 'acl' => ((local_user() && local_user() == $owner) ? populate_acl($channel_acl,false) : ''), + 'visitor' => true, + 'profile_uid' => intval($owner), + 'mimetype' => $mimetype, + 'layout' => $layout, + ); + + $o .= status_editor($a,$x); + + + // Get a list of webpages. We can't display all them because endless scroll makes that unusable, so just list titles and an edit link. + //TODO - this should be replaced with pagelist_widget + + $r = q("select * from item_id left join item on item_id.iid = item.id where item_id.uid = %d and service = 'WEBPAGE' order by item.created desc", + intval($owner) + ); + + $pages = null; + + if($r) { + $pages = array(); + foreach($r as $rr) { + unobscure($rr); + $pages[$rr['iid']][] = array('url' => $rr['iid'],'pagetitle' => $rr['sid'],'title' => $rr['title'],'created' => datetime_convert('UTC',date_default_timezone_get(),$rr['created']),'edited' => datetime_convert('UTC',date_default_timezone_get(),$rr['edited'])); + } + } + + +//Build the base URL for edit links + $url = z_root() . "/editwebpage/" . $which; +// This isn't pretty, but it works. Until I figure out what to do with the UI, it's Good Enough(TM). + return $o . replace_macros(get_markup_template("webpagelist.tpl"), array( + '$baseurl' => $url, + '$edit' => t('Edit'), + '$pages' => $pages, + '$channel' => $which, + '$view' => t('View'), + '$preview' => t('Preview'), + '$actions_txt' => t('Actions'), + '$pagelink_txt' => t('Page Link'), + '$title_txt' => t('Title'), + '$created_txt' => t('Created'), + '$edited_txt' => t('Edited') + +)); + + +} diff --git a/mod/wfinger.php b/mod/wfinger.php new file mode 100644 index 000000000..bdec92b54 --- /dev/null +++ b/mod/wfinger.php @@ -0,0 +1,111 @@ +<?php + +function wfinger_init(&$a) { + + $result = array(); + + $scheme = ''; + + if(x($_SERVER,'HTTPS') && $_SERVER['HTTPS']) + $scheme = 'https'; + elseif(x($_SERVER,'SERVER_PORT') && (intval($_SERVER['SERVER_PORT']) == 443)) + $scheme = 'https'; + + // Don't complain to me - I'm just implementing the spec. + + if($scheme !== 'https') { + header($_SERVER["SERVER_PROTOCOL"] . ' ' . 500 . ' ' . 'Webfinger requires HTTPS'); + killme(); + } + + $resource = $_REQUEST['resource']; + + + $r = null; + + if($resource) { + + if(strpos($resource,'acct:') === 0) { + $channel = str_replace('acct:','',$resource); + if(strpos($channel,'@') !== false) { + $host = substr($channel,strpos($channel,'@')+1); + if(strcasecmp($host,get_app()->get_hostname())) { + goaway('https://' . $host . '/.well-known/webfinger?resource=' . $resource); + } + $channel = substr($channel,0,strpos($channel,'@')); + } + } + if(strpos($resource,'http') === 0) { + $channel = str_replace('~','',basename($resource)); + } + + $r = q("select * from channel left join xchan on channel_hash = xchan_hash + where channel_address = '%s' limit 1", + dbesc($channel) + ); + + } + + + header('Access-Control-Allow-Origin: *'); + + header('Content-type: application/jrd+json'); + + + + if($resource && $r) { + + $result['subject'] = $resource; + + $aliases = array( + 'acct:' . $r[0]['channel_address'] . '@' . $a->get_hostname(), + z_root() . '/channel/' . $r[0]['channel_address'], + z_root() . '/~' . $r[0]['channel_address'] + ); + + $result['aliases'] = array(); + + $result['properties'] = array('http://webfinger.example/ns/name' => $r[0]['channel_name']); + + foreach($aliases as $alias) + if($alias != $resource) + $result['aliases'][] = $alias; + + + $result['links'] = array( + + array( + 'rel' => 'http://webfinger.example/rel/avatar', + 'type' => $r[0]['xchan_photo_mimetype'], + 'href' => $r[0]['xchan_photo_l'] + ), + + array( + 'rel' => 'http://webfinger.example/rel/profile-page', + 'href' => z_root() . '/profile/' . $r[0]['channel_address'], + ), + + array( + 'rel' => 'http://webfinger.example/rel/blog', + 'href' => z_root() . '/channel/' . $r[0]['channel_address'], + ), + + array( + 'rel' => 'http://purl.org/zot/protocol', + 'href' => z_root() . '/.well-known/zot-info' . '?address=' . $r[0]['xchan_addr'], + ) + ); + + } + else { + header($_SERVER["SERVER_PROTOCOL"] . ' ' . 400 . ' ' . 'Bad Request'); + killme(); + } + + $arr = array('channel' => $r[0], 'request' => $_REQUEST, 'result' => $result); + call_hooks('webfinger',$arr); + + echo json_encode($arr['result']); + killme(); + +}
\ No newline at end of file diff --git a/mod/xchan.php b/mod/xchan.php new file mode 100644 index 000000000..9d4cdcc22 --- /dev/null +++ b/mod/xchan.php @@ -0,0 +1,30 @@ +<?php + + +function xchan_content(&$a) { + + + $o .= '<h3>Xchan Lookup</h3>'; + + $o .= '<form action="xchan" method="get">'; + $o .= 'Lookup xchan beginning with: <input type="text" style="width: 250px;" name="addr" value="' . $_GET['addr'] .'" />'; + $o .= '<input type="submit" name="submit" value="Submit" /></form>'; + + $o .= '<br /><br />'; + + if(x($_GET,'addr')) { + $addr = trim($_GET['addr']); + + $r = q("select xchan_name from xchan where xchan_hash like '%s%%'", + dbesc($addr) + ); + + if($r) { + foreach($r as $rr) + $o .= $rr['xchan_name'] . EOL; + } + else + notice( t('Not found.') . EOL); + } + return $o; +} diff --git a/mod/xrd.php b/mod/xrd.php index d22ff4699..4d6a530e4 100644 --- a/mod/xrd.php +++ b/mod/xrd.php @@ -16,35 +16,34 @@ function xrd_init(&$a) { $name = substr($local,0,strpos($local,'@')); } - $r = q("SELECT * FROM `user` WHERE `nickname` = '%s' LIMIT 1", + $r = q("SELECT * FROM channel WHERE channel_address = '%s' LIMIT 1", dbesc($name) ); - if(! count($r)) + if(! $r) killme(); - $salmon_key = salmon_key($r[0]['pubkey']); +// $salmon_key = salmon_key($r[0]['pubkey']); header('Access-Control-Allow-Origin: *'); header("Content-type: text/xml"); - $dspr = ''; - $tpl = file_get_contents('view/xrd_person.tpl'); + $tpl = get_markup_template('view/xrd_person.tpl'); - $o = replace_macros($tpl, array( - '$nick' => $r[0]['nickname'], + $o = replace_macros(get_markup_template('xrd_person.tpl'), array( + '$nick' => $r[0]['channel_address'], '$accturi' => $uri, - '$profile_url' => $a->get_baseurl() . '/channel/' . $r[0]['nickname'], - '$hcard_url' => $a->get_baseurl() . '/hcard/' . $r[0]['nickname'], - '$atom' => $a->get_baseurl() . '/dfrn_poll/' . $r[0]['nickname'], - '$zot_post' => $a->get_baseurl() . '/post/' . $r[0]['nickname'], - '$poco_url' => $a->get_baseurl() . '/poco/' . $r[0]['nickname'], - '$photo' => $a->get_baseurl() . '/photo/profile/' . $r[0]['uid'], - '$dspr' => $dspr, - '$salmon' => $a->get_baseurl() . '/salmon/' . $r[0]['nickname'], - '$salmen' => $a->get_baseurl() . '/salmon/' . $r[0]['nickname'] . '/mention', - '$modexp' => 'data:application/magic-public-key,' . $salmon_key, - '$bigkey' => salmon_key($r[0]['pubkey']) + '$profile_url' => $a->get_baseurl() . '/channel/' . $r[0]['channel_address'], +// '$hcard_url' => $a->get_baseurl() . '/hcard/' . $r[0]['channel_address'], + '$atom' => $a->get_baseurl() . '/feed/' . $r[0]['channel_address'], + '$zot_post' => $a->get_baseurl() . '/post/' . $r[0]['channel_address'], + '$poco_url' => $a->get_baseurl() . '/poco/' . $r[0]['channel_address'], + '$photo' => $a->get_baseurl() . '/photo/profile/l/' . $r[0]['channel_id'], +// '$dspr' => $dspr, +// '$salmon' => $a->get_baseurl() . '/salmon/' . $r[0]['channel_address'], +// '$salmen' => $a->get_baseurl() . '/salmon/' . $r[0]['channel_address'] . '/mention', +// '$modexp' => 'data:application/magic-public-key,' . $salmon_key, +// '$bigkey' => salmon_key($r[0]['pubkey']) )); diff --git a/mod/xref.php b/mod/xref.php new file mode 100644 index 000000000..95cc22aa7 --- /dev/null +++ b/mod/xref.php @@ -0,0 +1,20 @@ +<?php + +function xref_init(&$a) { + // Sets a referral URL using an xchan directly + // Link format: example.com/xref/[xchan]/[TargetURL] + // Target URL is optional. + // Cookie lasts 24 hours to survive a browser restart. Contains no personal + // information at all - just somebody else's xchan. + $referrer = argv(1); + $expire=time()+60*60*2; + $path = 'xref'; + setcookie($path, $referrer, $expire, "/"); + $url = ''; + + if (argc() > 2) + $url = argv(2); + + goaway (z_root() . '/' . $url); + +} diff --git a/mod/zfinger.php b/mod/zfinger.php index 3452db68c..d79025885 100644 --- a/mod/zfinger.php +++ b/mod/zfinger.php @@ -52,10 +52,38 @@ function zfinger_init(&$a) { ); } elseif(strlen($zaddr)) { - $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash - where channel_address = '%s' limit 1", - dbesc($zaddr) - ); + if(strpos($zaddr,'[system]') === false) { /* normal address lookup */ + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where ( channel_address = '%s' or xchan_addr = '%s' ) limit 1", + dbesc($zaddr), + dbesc($zaddr) + ); + } + + else { + + /** + * The special address '[system]' will return a system channel if one has been defined, + * Or the first valid channel we find if there are no system channels. + * + * This is used by magic-auth if we have no prior communications with this site - and + * returns an identity on this site which we can use to create a valid hub record so that + * we can exchange signed messages. The precise identity is irrelevant. It's the hub + * information that we really need at the other end - and this will return it. + * + */ + + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where ( channel_pageflags & %d ) order by channel_id limit 1", + intval(PAGE_SYSTEM) + ); + if(! $r) { + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where not ( channel_pageflags & %d ) order by channel_id limit 1", + intval(PAGE_REMOVED) + ); + } + } } else { $ret['message'] = 'Invalid request'; @@ -71,10 +99,15 @@ function zfinger_init(&$a) { $id = $e['channel_id']; - $searchable = (($e['channel_pageflags'] & PAGE_HIDDEN) ? false : true); + $special_channel = (($e['channel_pageflags'] & PAGE_PREMIUM) ? true : false); + $adult_channel = (($e['channel_pageflags'] & PAGE_ADULT) ? true : false); + $censored = (($e['channel_pageflags'] & PAGE_CENSORED) ? true : false); + $searchable = (($e['channel_pageflags'] & PAGE_HIDDEN) ? false : true); + $deleted = (($e['xchan_flags'] & XCHAN_FLAGS_DELETED) ? true : false); + if(($e['xchan_flags'] & XCHAN_FLAGS_HIDDEN) || $deleted || $censored) + $searchable = false; - // This is for birthdays and keywords, but must check access permissions $p = q("select * from profile where uid = %d and is_default = 1", intval($e['channel_id']) @@ -83,10 +116,17 @@ function zfinger_init(&$a) { $profile = array(); if($p) { + + if(! intval($p[0]['publish'])) + $searchable = false; + $profile['description'] = $p[0]['pdesc']; $profile['birthday'] = $p[0]['dob']; - if($profile['birthday'] != '0000-00-00') - $profile['next_birthday'] = z_birthday($p[0]['dob'],$e['channel_timezone']); + if(($profile['birthday'] != '0000-00-00') && (($bd = z_birthday($p[0]['dob'],$e['channel_timezone'])) !== '')) + $profile['next_birthday'] = $bd; + + if($age = age($p[0]['dob'],$e['channel_timezone'],'')) + $profile['age'] = $age; $profile['gender'] = $p[0]['gender']; $profile['marital'] = $p[0]['marital']; $profile['sexual'] = $p[0]['sexual']; @@ -94,13 +134,20 @@ function zfinger_init(&$a) { $profile['region'] = $p[0]['region']; $profile['postcode'] = $p[0]['postal_code']; $profile['country'] = $p[0]['country_name']; + $profile['about'] = $p[0]['about']; + $profile['homepage'] = $p[0]['homepage']; + $profile['hometown'] = $p[0]['hometown']; + if($p[0]['keywords']) { $tags = array(); $k = explode(' ',$p[0]['keywords']); - if($k) - foreach($k as $kk) - if(trim($kk)) - $tags[] = trim($kk); + if($k) { + foreach($k as $kk) { + if(trim($kk," \t\n\r\0\x0B,")) { + $tags[] = trim($kk," \t\n\r\0\x0B,"); + } + } + } if($tags) $profile['keywords'] = $tags; } @@ -121,37 +168,50 @@ function zfinger_init(&$a) { $ret['photo_updated'] = $e['xchan_photo_date']; $ret['url'] = $e['xchan_url']; $ret['connections_url']= (($e['xchan_connurl']) ? $e['xchan_connurl'] : z_root() . '/poco/' . $e['channel_address']); - $ret['name_updated'] = $e['xchan_name_date']; $ret['target'] = $ztarget; $ret['target_sig'] = $zsig; $ret['searchable'] = $searchable; + $ret['adult_content'] = $adult_channel; + if($deleted) + $ret['deleted'] = $deleted; + + // premium or other channel desiring some contact with potential followers before connecting. + // This is a template - %s will be replaced with the follow_url we discover for the return channel. -// wtf -// if(! $e['xchan_connurl']) - -// FIXME encrypt permissions when targeted so that only the target can view them, requires sending the pubkey and also checking that the target_sig is signed with that pubkey and isn't a forgery. + if($special_channel) + $ret['connect_url'] = z_root() . '/connect/' . $e['channel_address']; - logger('zot-info: ' . print_r($e,true)); + // This is a template for our follow url, %s will be replaced with a webbie - $permissions = get_all_perms($e['channel_id'],(($ztarget && $zsig) + $ret['follow_url'] = z_root() . '/follow?f=&url=%s'; + + $ztarget_hash = (($ztarget && $zsig) ? base64url_encode(hash('whirlpool',$ztarget . $zsig,true)) - : '' ),false); + : '' ); + $permissions = get_all_perms($e['channel_id'],$ztarget_hash,false); + + if($ztarget_hash) { + $permissions['connected'] = false; + $b = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", + dbesc($ztarget_hash), + intval($e['channel_id']) + ); + if($b) + $permissions['connected'] = true; + } $ret['permissions'] = (($ztarget && $zkey) ? aes_encapsulate(json_encode($permissions),$zkey) : $permissions); if($permissions['view_profile']) $ret['profile'] = $profile; -// if($feed && $permissions['view_stream']) -// $ret['messages'] = $zot_feed($e['channel_id'],(($ztarget && $zsig) -// ? base64url_encode(hash('whirlpool',$ztarget . $zsig,true)) -// : '' ),$mindate); // array of (verified) hubs this channel uses $ret['locations'] = array(); - $x = zot_get_hubloc(array($e['channel_hash'])); + + $x = zot_get_hublocs($e['channel_hash']); if($x && count($x)) { foreach($x as $hub) { if(! ($hub['hubloc_flags'] & HUBLOC_FLAGS_UNVERIFIED)) { @@ -162,7 +222,8 @@ function zfinger_init(&$a) { 'url' => $hub['hubloc_url'], 'url_sig' => $hub['hubloc_url_sig'], 'callback' => $hub['hubloc_callback'], - 'sitekey' => $hub['hubloc_sitekey'] + 'sitekey' => $hub['hubloc_sitekey'], + 'deleted' => (($hub['hubloc_flags'] & HUBLOC_FLAGS_DELETED) ? true : false) ); } } @@ -170,6 +231,8 @@ function zfinger_init(&$a) { $ret['site'] = array(); $ret['site']['url'] = z_root(); + $ret['site']['url_sig'] = base64url_encode(rsa_sign(z_root(),$e['channel_prvkey'])); + $dirmode = get_config('system','directory_mode'); if(($dirmode === false) || ($dirmode == DIRECTORY_MODE_NORMAL)) $ret['site']['directory_mode'] = 'normal'; @@ -180,8 +243,62 @@ function zfinger_init(&$a) { elseif($dirmode == DIRECTORY_MODE_STANDALONE) $ret['site']['directory_mode'] = 'standalone'; if($dirmode != DIRECTORY_MODE_NORMAL) - $ret['site']['directory_url'] = z_root() . '/dir'; - + $ret['site']['directory_url'] = z_root() . '/dirsearch'; + + + // hide detailed site information if you're off the grid + + if($dirmode != DIRECTORY_MODE_STANDALONE) { + + $register_policy = intval(get_config('system','register_policy')); + + + if($register_policy == REGISTER_CLOSED) + $ret['site']['register_policy'] = 'closed'; + if($register_policy == REGISTER_APPROVE) + $ret['site']['register_policy'] = 'approve'; + if($register_policy == REGISTER_OPEN) + $ret['site']['register_policy'] = 'open'; + + + $access_policy = intval(get_config('system','access_policy')); + + if($access_policy == ACCESS_PRIVATE) + $ret['site']['access_policy'] = 'private'; + if($access_policy == ACCESS_PAID) + $ret['site']['access_policy'] = 'paid'; + if($access_policy == ACCESS_FREE) + $ret['site']['access_policy'] = 'free'; + if($access_policy == ACCESS_TIERED) + $ret['site']['access_policy'] = 'tiered'; + + require_once('include/account.php'); + $ret['site']['accounts'] = account_total(); + + require_once('include/identity.php'); + $ret['site']['channels'] = channel_total(); + + + $ret['site']['version'] = RED_PLATFORM . ' ' . RED_VERSION . '[' . DB_UPDATE_VERSION . ']'; + + $ret['site']['admin'] = get_config('system','admin_email'); + + $visible_plugins = array(); + if(is_array($a->plugins) && count($a->plugins)) { + $r = q("select * from addon where hidden = 0"); + if($r) + foreach($r as $rr) + $visible_plugins[] = $rr['name']; + } + + $ret['site']['plugins'] = $visible_plugins; + $ret['site']['sitehash'] = get_config('system','location_hash'); + $ret['site']['sitename'] = get_config('system','sitename'); + $ret['site']['sellpage'] = get_config('system','sellpage'); + $ret['site']['location'] = get_config('system','site_location'); + + } + call_hooks('zot_finger',$ret); json_return_and_die($ret); -}
\ No newline at end of file +} diff --git a/mod/zotfeed.php b/mod/zotfeed.php index 6519481d2..480e886cd 100644 --- a/mod/zotfeed.php +++ b/mod/zotfeed.php @@ -9,24 +9,35 @@ function zotfeed_init(&$a) { $mindate = (($_REQUEST['mindate']) ? datetime_convert('UTC','UTC',$_REQUEST['mindate']) : ''); if(! $mindate) - $mindate = '0000-00-00 00:00:00'; + $mindate = datetime_convert('UTC','UTC', 'now - 1 month'); if(get_config('system','block_public') && (! get_account_id()) && (! remote_user())) { $result['message'] = 'Public access denied'; json_return_and_die($result); } + $observer = $a->get_observer(); + + $channel_address = ((argc() > 1) ? argv(1) : ''); if($channel_address) { - $r = q("select channel_id from channel where channel_address = '%s' limit 1", - dbesc(argv(1)) + $r = q("select channel_id, channel_name from channel where channel_address = '%s' and not (channel_pageflags & %d) limit 1", + dbesc(argv(1)), + intval(PAGE_REMOVED) ); } + else { + $x = get_sys_channel(); + if($x) + $r = array($x); + } if(! $r) { $result['message'] = 'Channel not found.'; json_return_and_die($result); } + logger('zotfeed request: ' . $r[0]['channel_name'], LOGGER_DEBUG); + $result['messages'] = zot_feed($r[0]['channel_id'],$observer['xchan_hash'],$mindate); $result['success'] = true; json_return_and_die($result); diff --git a/mod/zperms.php b/mod/zperms.php deleted file mode 100644 index 6a7097cd6..000000000 --- a/mod/zperms.php +++ /dev/null @@ -1,84 +0,0 @@ -<?php - -function zperms_init(&$a) { - - require_once('include/zot.php'); - require_once('include/Contact.php'); - require_once('include/crypto.php'); - - $ret = array('success' => false); - - $zguid = ((x($_REQUEST,'guid')) ? $_REQUEST['guid'] : ''); - $zaddr = ((x($_REQUEST,'address')) ? $_REQUEST['address'] : ''); - $ztarget = ((x($_REQUEST,'target')) ? $_REQUEST['target'] : ''); - $zsig = ((x($_REQUEST,'target_sig')) ? $_REQUEST['target_sig'] : ''); - - $r = null; - - if(strlen($zguid)) { - $r = q("select * from channel where channel_guid = '%s' limit 1", - dbesc($zguid) - ); - } - elseif(strlen($zaddr)) { - $r = q("select * from channel where channel_address = '%s' limit 1", - dbesc($zaddr) - ); - } - else { - $ret['message'] = 'Invalid request'; - json_return_and_die($ret); - } - - if(! ($r && count($r))) { - $ret['message'] = 'Item not found.'; - json_return_and_die($ret); - } - $e = $r[0]; - - $id = $e['channel_id']; - $r = q("select contact.*, profile.* - from contact left join profile on contact.uid = profile.uid - where contact.uid = %d && contact.self = 1 and profile.is_default = 1 limit 1", - intval($id) - ); - if($r && count($r)) { - $profile = $r[0]; - } - - - - $ret['success'] = true; - $ret['guid'] = $e['channel_guid']; - $ret['guid_sig'] = base64url_encode(rsa_sign($e['channel_guid'],$e['channel_prvkey'])); - $ret['key'] = $e['channel_pubkey']; - $ret['name'] = $e['channel_name']; - $ret['address'] = $e['channel_address']; - $ret['target'] = $ztarget; - $ret['target_sig'] = $zsig; - $ret['permissions'] = map_perms($r[0],$ztarget,$zsig); - - $ret['profile'] = $profile; - - // array of (verified) hubs this channel uses - - $ret['hubs'] = array(); - $x = zot_get_hubloc(array($e['channel_guid'])); - if($x && count($x)) { - foreach($x as $hub) { - if(! ($hub['hubloc_flags'] & HUBLOC_FLAGS_UNVERIFIED)) { - $ret['hubs'][] = array( - 'primary' => (($hub['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY) ? true : false), - 'url' => $hub['hubloc_url'], - /// hmmm we probably shouldn't sign somebody else's hub. FIXME - 'url_sig' => base64url_encode(rsa_sign($hub['hubloc_url'],$e['channel_prvkey'])), - 'callback' => $hub['hubloc_callback'], - 'sitekey' => $hub['hubloc_sitekey'] - ); - } - } - } - - json_return_and_die($ret); - -} diff --git a/mod/zping.php b/mod/zping.php new file mode 100644 index 000000000..76f4470c1 --- /dev/null +++ b/mod/zping.php @@ -0,0 +1,28 @@ +<?php /** @file */ + +require_once('include/zot.php'); + +function zping_content(&$a) { + + // This is just a test utility function and may go away once we build these tools into + // the address book and directory to do dead site discovery. + + // The response packet include the current URL and key so we can discover if the server + // has been re-installed and clean up (e.g. get rid of) any old hublocs and xchans. + + // Remember to add '/post' to the url + + if(! local_user()) + return; + + $url = $_REQUEST['url']; + + if(! $url) + return; + + + $m = zot_build_packet($a->get_channel(),'ping'); + $r = zot_zot($url,$m); + return print_r($r,true); + +}
\ No newline at end of file |