From 050bae56c24d61712b62655f1fc8319c58b24ed3 Mon Sep 17 00:00:00 2001 From: Friendika Date: Tue, 14 Dec 2010 00:39:46 -0800 Subject: [PATCH 1/6] upd8 --- README | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/README b/README index 9538dbe7a..e3eae2cdc 100644 --- a/README +++ b/README @@ -1,14 +1,20 @@ - Friendika - Distributed Social Network + ********* + Friendika + ********* - http://friendika.com + Distributed Social Network -What if there was a social network which was free to use, open source - and -where your privacy is always under your control? + http://friendika.com -What if this social network could scale to encompass the entire internet, and -*not* require a central organisation to provide servers (in exchange for +Did you ever wonder what might happen if you ever left Facebook? + +What if there was a social network which provided some of the same interaction +you've grown to love, *and* was free to use, open source - and where your +privacy is always under your control? + +And what if this social network could scale to encompass the entire internet, +and *not* require a central organisation to provide servers (in exchange for selling your private information to advertisers)? Look no further. From 7a174c1cc87330bcfd7facefa89a596ce701edc3 Mon Sep 17 00:00:00 2001 From: Friendika Date: Tue, 14 Dec 2010 00:56:54 -0800 Subject: [PATCH 2/6] upd8 --- README | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README b/README index e3eae2cdc..7c81097a3 100644 --- a/README +++ b/README @@ -18,7 +18,7 @@ and *not* require a central organisation to provide servers (in exchange for selling your private information to advertisers)? Look no further. - + Friendika is a social network without boundaries. Friendika installations can link together into a global social network which is free from central control. Besides the Friendika network [which is privacy enhanced]; you can @@ -42,7 +42,10 @@ Friendika is secure, and as private as you wish it to be. Our privacy settings are straight-forward and simple, because we know that relationships rarely are (straight-forward and simple). Whether you're communicating with drinking buddies or potential employers, you can rest assured that each is only able to -see the side of you that you wish to present. +see the side of you that you wish to present. If you send a private message to +your aunt Mary, we encrypt it with military grade encryption. Other social +networks talk about privacy and offering a feature-rich social networking +alternative, but Friendika delivers. Time and time again. A single instance of Friendika can easily support hundreds of (and up to several thousand) people using commodity hosting hardware. Each of these From 46bc84b2f26fd1370a89a8954d743f23925a4a11 Mon Sep 17 00:00:00 2001 From: Friendika Date: Tue, 14 Dec 2010 01:13:39 -0800 Subject: [PATCH 3/6] upd8 --- README | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README b/README index 7c81097a3..e07e95320 100644 --- a/README +++ b/README @@ -43,9 +43,11 @@ are straight-forward and simple, because we know that relationships rarely are (straight-forward and simple). Whether you're communicating with drinking buddies or potential employers, you can rest assured that each is only able to see the side of you that you wish to present. If you send a private message to -your aunt Mary, we encrypt it with military grade encryption. Other social -networks talk about privacy and offering a feature-rich social networking -alternative, but Friendika delivers. Time and time again. +your aunt Mary, we encrypt it with military grade encryption. + +Other social network projects talk about privacy and offering a feature-rich +social networking alternative, but all they can deliver is vapour and vague +promises. Friendika delivers the goods. Time and time again. A single instance of Friendika can easily support hundreds of (and up to several thousand) people using commodity hosting hardware. Each of these From 78d8bcbc6023ae62d84c77cd91619bf0f016d376 Mon Sep 17 00:00:00 2001 From: Friendika Date: Tue, 14 Dec 2010 14:15:31 -0800 Subject: [PATCH 4/6] personal config storage, template the vcard profile, logging failed uri's to help track down transient dreamhost issues --- README | 2 +- boot.php | 204 ++++++++++++++++++++++++++++++++++- database.sql | 10 ++ index.php | 1 + update.php | 9 ++ view/profile_vcard.tpl | 26 +++++ view/theme/default/style.css | 21 +++- 7 files changed, 266 insertions(+), 7 deletions(-) create mode 100644 view/profile_vcard.tpl diff --git a/README b/README index e07e95320..f35b8c0cf 100644 --- a/README +++ b/README @@ -43,7 +43,7 @@ are straight-forward and simple, because we know that relationships rarely are (straight-forward and simple). Whether you're communicating with drinking buddies or potential employers, you can rest assured that each is only able to see the side of you that you wish to present. If you send a private message to -your aunt Mary, we encrypt it with military grade encryption. +your aunt Mary, we encrypt it with military grade encryption. Other social network projects talk about privacy and offering a feature-rich social networking alternative, but all they can deliver is vapour and vague diff --git a/boot.php b/boot.php index 4625f64f0..1546429c3 100644 --- a/boot.php +++ b/boot.php @@ -2,7 +2,7 @@ set_time_limit(0); -define ( 'BUILD_ID', 1022 ); +define ( 'BUILD_ID', 1023 ); define ( 'DFRN_PROTOCOL_VERSION', '2.0' ); define ( 'EOL', "
\r\n" ); @@ -157,6 +157,7 @@ if(! class_exists('App')) { class App { public $module_loaded = false; + public $query_string; public $config; public $page; public $profile; @@ -189,6 +190,8 @@ class App { $this->page = array(); $this->pager= array(); + $this->query_string = ''; + $this->scheme = ((isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'])) ? 'https' : 'http' ); if(x($_SERVER,'SERVER_NAME')) @@ -197,7 +200,7 @@ class App { set_include_path("include/$this->hostname" . PATH_SEPARATOR . 'include' . PATH_SEPARATOR . '.' ); if((x($_SERVER,'QUERY_STRING')) && substr($_SERVER['QUERY_STRING'],0,2) === "q=") - $_SERVER['QUERY_STRING'] = substr($_SERVER['QUERY_STRING'],2); + $this->query_string = substr($_SERVER['QUERY_STRING'],2); if(x($_GET,'q')) $this->cmd = trim($_GET['q'],'/'); @@ -881,7 +884,7 @@ function hex2bin($s) { if(! function_exists('paginate')) { function paginate(&$a) { $o = ''; - $stripped = preg_replace('/(&page=[0-9]*)/','',$_SERVER['QUERY_STRING']); + $stripped = preg_replace('/(&page=[0-9]*)/','',$a->query_string); $stripped = str_replace('q=','',$stripped); $stripped = trim($stripped,'/'); $url = $a->get_baseurl() . '/' . $stripped; @@ -1040,6 +1043,96 @@ function set_config($family,$key,$value) { return $ret; }} + +if(! function_exists('get_pconfig')) { +function get_pconfig($uid,$family, $key, $instore = false) { + + global $a; + + if(! $instore) { + if(isset($a->config[$uid][$family][$key])) { + if($a->config[$uid][$family][$key] === '!!') { + return false; + } + return $a->config[$uid][$family][$key]; + } + } + $ret = q("SELECT `v` FROM `pconfig` WHERE `uid` = %d AND `cat` = '%s' AND `k` = '%s' LIMIT 1", + intval($uid), + dbesc($family), + dbesc($key) + ); + if(count($ret)) { + $a->config[$uid][$family][$key] = $ret[0]['v']; + return $ret[0]['v']; + } + else { + $a->config[$uid][$family][$key] = '!!'; + } + return false; +}} + +if(! function_exists('del_config')) { +function del_config($family,$key) { + + global $a; + if(x($a->config[$family],$key)) + unset($a->config[$family][$key]); + $ret = q("DELETE FROM `config` WHERE `cat` = '%s' AND `k` = '%s' LIMIT 1", + dbesc($cat), + dbesc($key) + ); + return $ret; +}} + + + +// Same as above functions except these are for personal config storage and take an +// additional $uid argument. + +if(! function_exists('set_pconfig')) { +function set_pconfig($uid,$family,$key,$value) { + + global $a; + $a->config[$uid][$family][$key] = $value; + + if(get_pconfig($uid,$family,$key,true) === false) { + $ret = q("INSERT INTO `pconfig` ( `uid`, `cat`, `k`, `v` ) VALUES ( %d, '%s', '%s', '%s' ) ", + intval($uid), + dbesc($family), + dbesc($key), + dbesc($value) + ); + if($ret) + return $value; + return $ret; + } + $ret = q("UPDATE `pconfig` SET `v` = '%s' WHERE `uid` = %d AND `cat` = '%s' AND `k` = '%s' LIMIT 1", + intval($uid), + dbesc($value), + dbesc($family), + dbesc($key) + ); + if($ret) + return $value; + return $ret; +}} + +if(! function_exists('del_pconfig')) { +function del_pconfig($uid,$family,$key) { + + global $a; + if(x($a->config[$uid][$family],$key)) + unset($a->config[$uid][$family][$key]); + $ret = q("DELETE FROM `pconfig` WHERE `uid` = %d AND `cat` = '%s' AND `k` = '%s' LIMIT 1", + intval($uid), + dbesc($cat), + dbesc($key) + ); + return $ret; +}} + + // convert an XML document to a normalised, case-corrected array // used by webfinger @@ -1654,12 +1747,34 @@ function aes_encrypt($val,$ky) return mcrypt_encrypt($enc, $key, $val, $mode, mcrypt_create_iv( mcrypt_get_iv_size($enc, $mode), MCRYPT_DEV_URANDOM)); }} + +/** + * + * Function: linkify + * + * Replace naked text hyperlink with HTML formatted hyperlink + * + */ + if(! function_exists('linkify')) { function linkify($s) { $s = preg_replace("/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\.\=\_\~\#\'\%]*)/", ' $1', $s); return($s); }} + +/** + * + * Function: smilies + * + * Description: + * Replaces text emoticons with graphical images + * + * @Parameter: string $s + * + * Returns string + */ + if(! function_exists('smilies')) { function smilies($s) { $a = get_app(); @@ -1739,14 +1854,95 @@ function profile_load(&$a, $nickname, $profile = 0) { $a->profile = $r[0]; - $a->page['template'] = 'profile'; $a->page['title'] = $a->profile['name']; $_SESSION['theme'] = $a->profile['theme']; if(! (x($a->page,'aside'))) $a->page['aside'] = ''; + + $a->page['aside'] .= profile_sidebar($a->profile); $a->page['aside'] .= contact_block(); return; }} + + +/** + * + * Function: profile_sidebar + * + * Formats a profile for display in the sidebar. + * It is very difficult to templatise the HTML completely + * because of all the conditional logic. + * + * @parameter: array $profile + * + * Returns HTML string stuitable for sidebar inclusion + * Exceptions: Returns empty string if passed $profile is wrong type or not populated + * + */ + + +if(! function_exists('profile_sidebar')) { +function profile_sidebar($profile) { + + $o = ''; + $location = ''; + $address = false; + + if((! is_array($profile)) && (! count($profile))) + return $o; + + $fullname = '
' . $profile['name'] . '
'; + + $tabs = ''; + + $photo = '
' . $profile['name'] . '
'; + + $connect = (($profile['uid'] != local_user()) ? '
  • ' . t('Connect') . '
  • ' : ''); + + if((x($profile,'address') == 1) + || (x($profile,'locality') == 1) + || (x($profile,'region') == 1) + || (x($profile,'postal-code') == 1) + || (x($profile,'country-name') == 1)) + $address = true; + + if($address) { + $location .= '
    ' . t('Location:') . '
    '; + $location .= ((x($profile,'address') == 1) ? '
    ' . $profile['address'] . '
    ' : ''); + $location .= (((x($profile,'locality') == 1) || (x($profile,'region') == 1) || (x($profile,'postal-code') == 1)) + ? '' . $profile['locality'] . '' + . ((x($profile['locality']) == 1) ? t(', ') : '') + . '' . $profile['region'] . '' + . ' ' . $profile['postal-code'] . '' : ''); + $location .= ((x($profile,'country-name') == 1) ? ' ' . $profile['country-name'] . '' : ''); + $location .= '
    '; + + } + + $gender = ((x($profile,'gender') == 1) ? '
    ' . t('Gender:') . ' ' . $profile['gender'] . '
    ' : ''); + + $pubkey = ((x($profile,'key') == 1) ? '' : ''); + + $marital = ((x($profile,'marital') == 1) ? '
    ' . t('Status:') . ' ' . $profile['marital'] . '
    ' : ''); + + $homepage = ((x($profile,'homepage') == 1) ? '
    ' . t('Homepage:') . ' ' . linkify($profile['homepage']) . '
    ' : ''); + + $tpl = load_view_file('view/profile_vcard.tpl'); + + $o .= replace_macros($tpl, array( + '$fullname' => $fullname, + '$tabs' => $tabs, + '$photo' => $photo, + '$connect' => $connect, + '$location' => $location, + '$gender' => $gender, + '$pubkey' => $pubkey, + '$marital' => $marital, + '$homepage' => $homepage + )); + + return $o; +}} \ No newline at end of file diff --git a/database.sql b/database.sql index 0b322e9e0..148a8d0d8 100644 --- a/database.sql +++ b/database.sql @@ -419,3 +419,13 @@ CREATE TABLE IF NOT EXISTS `queue` ( `last` DATETIME NOT NULL , `content` MEDIUMTEXT NOT NULL ) ENGINE = MYISAM DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `pconfig` ( +`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , +`uid` INT NOT NULL DEFAULT '0', +`cat` CHAR( 255 ) NOT NULL , +`k` CHAR( 255 ) NOT NULL , +`v` MEDIUMTEXT NOT NULL +) ENGINE = MYISAM DEFAULT CHARSET=utf8; + + diff --git a/index.php b/index.php index e91603a30..2f56d5414 100644 --- a/index.php +++ b/index.php @@ -131,6 +131,7 @@ if(strlen($a->module)) { $a->module_loaded = true; } else { + logger('index.php: page not found: ' . $_SERVER['REQUEST_URI'] . ' QUERY: ' . $_SERVER['QUERY_STRING'], LOGGER_DEBUG); header($_SERVER["SERVER_PROTOCOL"] . ' 404 ' . t('Not Found')); notice( t('Page not found.' ) . EOL); } diff --git a/update.php b/update.php index 92b240798..b3fab6720 100644 --- a/update.php +++ b/update.php @@ -228,3 +228,12 @@ function update_1021() { q("ALTER TABLE `item` ADD `private` TINYINT( 1 ) NOT NULL DEFAULT '0' AFTER `deny_gid` "); } +function update_1022() { + q("CREATE TABLE `pconfig` ( + `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , + `uid` INT NOT NULL DEFAULT '0', + `cat` CHAR( 255 ) NOT NULL , + `k` CHAR( 255 ) NOT NULL , + `v` MEDIUMTEXT NOT NULL + ) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci "); +} diff --git a/view/profile_vcard.tpl b/view/profile_vcard.tpl new file mode 100644 index 000000000..81659af6a --- /dev/null +++ b/view/profile_vcard.tpl @@ -0,0 +1,26 @@ +
    + + $fullname + + $tabs + + $photo + + + + $location + + $gender + + $pubkey + +
    + +$marital + +$homepage + diff --git a/view/theme/default/style.css b/view/theme/default/style.css index f20341dd6..491486794 100644 --- a/view/theme/default/style.css +++ b/view/theme/default/style.css @@ -188,7 +188,7 @@ img.photo { .heart { color: #FF0000; - font-size: 120%; + font-size: 100%; } aside { @@ -1893,4 +1893,21 @@ a.mail-list-link { #search-box { margin-bottom: 25px; -} \ No newline at end of file +} + +.location-label, .gender-label, .marital-label, .homepage-label { + float: left; + text-align: right; + display: block; + width: 65px; +} + +.adr, .x-gender, .marital-text, .homepage-url { + float: left; + display: block; + margin-left: 8px; +} + +.profile-clear { + clear: both; +} From d8c5c1cd6bf1a11dbbe8f1794f9d633251b75803 Mon Sep 17 00:00:00 2001 From: Friendika Date: Tue, 14 Dec 2010 15:21:31 -0800 Subject: [PATCH 5/6] added brand link --- include/nav.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nav.php b/include/nav.php index 77cffc3ab..f7c5c4e01 100644 --- a/include/nav.php +++ b/include/nav.php @@ -55,7 +55,7 @@ if($banner === false) - $banner .= 'logoFriendika'; + $banner .= 'logoFriendika'; $a->page['nav'] .= ''; From 83939f1541219c38f03b90f525ea48512f912323 Mon Sep 17 00:00:00 2001 From: Friendika Date: Tue, 14 Dec 2010 16:34:49 -0800 Subject: [PATCH 6/6] clean up comments --- mod/dfrn_request.php | 131 ++++++++++++++++++++++++++++++------------- 1 file changed, 93 insertions(+), 38 deletions(-) diff --git a/mod/dfrn_request.php b/mod/dfrn_request.php index e1370dfd8..65a2c771e 100644 --- a/mod/dfrn_request.php +++ b/mod/dfrn_request.php @@ -1,5 +1,14 @@ argv[1]; profile_load($a,$which); - return; }} +/** + * Function: dfrn_request_post + * + * Purpose: + * Handles multiple scenarios. + * + * Scenario 1: + * Clicking 'submit' on a friend request page. + * + * Scenario 2: + * Following Scenario 1, we are brought back to our home site + * in order to link our friend request with our own server cell. + * After logging in, we click 'submit' to approve the linkage. + * + */ + if(! function_exists('dfrn_request_post')) { function dfrn_request_post(&$a) { @@ -24,24 +48,34 @@ function dfrn_request_post(&$a) { } - // We've introduced ourself to another cell, then have been returned to our own cell - // to confirm the request, and then we've clicked submit (perhaps after logging in). - // That brings us here: + /** + * + * Scenario 2: We've introduced ourself to another cell, then have been returned to our own cell + * to confirm the request, and then we've clicked submit (perhaps after logging in). + * That brings us here: + * + */ if((x($_POST,'localconfirm')) && ($_POST['localconfirm'] == 1)) { - // Ensure this is a valid request - + /** + * Ensure this is a valid request + */ + if(local_user() && ($a->user['nickname'] == $a->argv[1]) && (x($_POST,'dfrn_url'))) { - $dfrn_url = notags(trim($_POST['dfrn_url'])); - $aes_allow = (((x($_POST,'aes_allow')) && ($_POST['aes_allow'] == 1)) ? 1 : 0); + $dfrn_url = notags(trim($_POST['dfrn_url'])); + $aes_allow = (((x($_POST,'aes_allow')) && ($_POST['aes_allow'] == 1)) ? 1 : 0); $confirm_key = ((x($_POST,'confirm_key')) ? $_POST['confirm_key'] : ""); $contact_record = null; if(x($dfrn_url)) { + + /** + * Lookup the contact based on their URL (which is the only unique thing we have at the moment) + */ $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `url` = '%s' AND `self` = 0 LIMIT 1", intval(local_user()), @@ -50,6 +84,11 @@ function dfrn_request_post(&$a) { if(count($r)) { if(strlen($r[0]['dfrn-id'])) { + + /** + * We don't need to be here. It has already happened. + */ + notice( t("This introduction has already been accepted.") . EOL ); return; } @@ -65,9 +104,12 @@ function dfrn_request_post(&$a) { } else { + /** + * Scrape the other site's profile page to pick up the dfrn links, key, fn, and photo + */ + require_once('Scrape.php'); - $parms = scrape_dfrn($dfrn_url); if(! count($parms)) { @@ -88,12 +130,17 @@ function dfrn_request_post(&$a) { } } - - $dfrn_request = $parms['dfrn-request']; + /********* Escape the entire array ********/ + dbesc_array($parms); + /******************************************/ + + /** + * Create a contact record on our site for the other person + */ $r = q("INSERT INTO `contact` ( `uid`, `created`,`url`, `name`, `nick`, `photo`, `site-pubkey`, `request`, `confirm`, `notify`, `poll`, `aes_allow`) @@ -117,14 +164,18 @@ function dfrn_request_post(&$a) { notice( t("Introduction complete.") . EOL); } - // Allow the blocked remote notification to complete + /** + * Allow the blocked remote notification to complete + */ if(is_array($contact_record)) $dfrn_request = $contact_record['request']; if(strlen($dfrn_request) && strlen($confirm_key)) $s = fetch_url($dfrn_request . '?confirm_key=' . $confirm_key); - // ignore reply + + // (ignore reply, nothing we can do it failed) + goaway($dfrn_url); return; // NOTREACHED @@ -139,23 +190,27 @@ function dfrn_request_post(&$a) { return; // NOTREACHED } - // Otherwise: - - // We are the requestee. A person from a remote cell has made an introduction - // on our profile web page and clicked submit. We will use their DFRN-URL to - // figure out how to contact their cell. - - // Scrape the originating DFRN-URL for everything we need. Create a contact record - // and an introduction to show our user next time he/she logs in. - // Finally redirect back to the requestor so that their site can record the request. - // If our user (the requestee) later confirms this request, a record of it will need - // to exist on the requestor's cell in order for the confirmation process to complete.. - - // It's possible that neither the requestor or the requestee are logged in at the moment, - // and the requestor does not yet have any credentials to the requestee profile. - - // Who is the requestee? We've already loaded their profile which means their nickname should be - // in $a->argv[1] and we should have their complete info in $a->profile. + /** + * Otherwise: + * + * Scenario 1: + * We are the requestee. A person from a remote cell has made an introduction + * on our profile web page and clicked submit. We will use their DFRN-URL to + * figure out how to contact their cell. + * + * Scrape the originating DFRN-URL for everything we need. Create a contact record + * and an introduction to show our user next time he/she logs in. + * Finally redirect back to the requestor so that their site can record the request. + * If our user (the requestee) later confirms this request, a record of it will need + * to exist on the requestor's cell in order for the confirmation process to complete.. + * + * It's possible that neither the requestor or the requestee are logged in at the moment, + * and the requestor does not yet have any credentials to the requestee profile. + * + * Who is the requestee? We've already loaded their profile which means their nickname should be + * in $a->argv[1] and we should have their complete info in $a->profile. + * + */ if(! (is_array($a->profile) && count($a->profile))) { notice( t('Profile unavailable.') . EOL); @@ -343,14 +398,14 @@ function dfrn_request_post(&$a) { elseif($network === 'stat') { /** - * - * OStatus network - * Check contact existence - * Try and scrape together enough information to create a contact record, with us as REL_VIP - * Substitute our user's feed URL into $url template - * Send the subscriber home to subscribe - * - **/ + * + * OStatus network + * Check contact existence + * Try and scrape together enough information to create a contact record, with us as REL_VIP + * Substitute our user's feed URL into $url template + * Send the subscriber home to subscribe + * + */ $url = str_replace('{uri}', $a->get_baseurl() . '/dfrn_poll/' . $nickname, $url); goaway($url);