aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorChris Case <kahotep@bunda.dreamhost.com>2011-05-21 21:40:16 -0700
committerChris Case <kahotep@bunda.dreamhost.com>2011-05-21 21:40:16 -0700
commit4cff911939b263993eb41682ca558c975e2db01f (patch)
tree78f58e08d04413827744689d0f5df7660bee6caa /include
parent2cf696d0b5d647e1741d2f94ee379aa19b25ae1b (diff)
parentf3f063c0dd7fd8b706987b856d79c7b58924acbb (diff)
downloadvolse-hubzilla-4cff911939b263993eb41682ca558c975e2db01f.tar.gz
volse-hubzilla-4cff911939b263993eb41682ca558c975e2db01f.tar.bz2
volse-hubzilla-4cff911939b263993eb41682ca558c975e2db01f.zip
merged multipart email changes
Diffstat (limited to 'include')
-rw-r--r--include/Contact.php5
-rw-r--r--include/Photo.php12
-rw-r--r--include/Scrape.php288
-rw-r--r--include/acl_selectors.php13
-rw-r--r--include/api.php431
-rw-r--r--include/auth.php21
-rw-r--r--include/bbcode.php17
-rw-r--r--include/conversation.php755
-rw-r--r--include/dba.php19
-rw-r--r--include/email.php201
-rw-r--r--include/expire.php44
-rw-r--r--include/fcontact.php41
-rw-r--r--include/group.php24
-rw-r--r--include/hostxrd.php4
-rw-r--r--include/items.php288
-rw-r--r--include/main.js103
-rw-r--r--include/nav.php68
-rw-r--r--include/notifier.php137
-rw-r--r--include/pgettext.php46
-rw-r--r--include/poller.php217
-rw-r--r--include/profile_advanced.php258
-rw-r--r--include/salmon.php2
-rw-r--r--include/security.php2
-rw-r--r--include/template_processor.php137
24 files changed, 2973 insertions, 160 deletions
diff --git a/include/Contact.php b/include/Contact.php
index 7cac3c0e0..4ca77d065 100644
--- a/include/Contact.php
+++ b/include/Contact.php
@@ -14,11 +14,13 @@ function user_remove($uid) {
q("DELETE FROM `group` WHERE `uid` = %d", intval($uid));
q("DELETE FROM `group_member` WHERE `uid` = %d", intval($uid));
q("DELETE FROM `intro` WHERE `uid` = %d", intval($uid));
+ q("DELETE FROM `event` WHERE `uid` = %d", intval($uid));
q("DELETE FROM `item` WHERE `uid` = %d", intval($uid));
q("DELETE FROM `mail` WHERE `uid` = %d", intval($uid));
q("DELETE FROM `photo` WHERE `uid` = %d", intval($uid));
q("DELETE FROM `profile` WHERE `uid` = %d", intval($uid));
q("DELETE FROM `profile_check` WHERE `uid` = %d", intval($uid));
+ q("DELETE FROM `pconfig` WHERE `uid` = %d", intval($uid));
q("DELETE FROM `user` WHERE `uid` = %d", intval($uid));
if($uid == local_user()) {
unset($_SESSION['authenticated']);
@@ -41,6 +43,9 @@ function contact_remove($id) {
q("DELETE FROM `mail` WHERE `contact-id` = %d ",
intval($id)
);
+ q("DELETE FROM `event` WHERE `cid` = %d ",
+ intval($id)
+ );
}
diff --git a/include/Photo.php b/include/Photo.php
index 9934b9a39..707b0de5d 100644
--- a/include/Photo.php
+++ b/include/Photo.php
@@ -162,12 +162,20 @@ class Photo {
}
public function saveImage($path) {
- imagejpeg($this->image,$path,100);
+ $quality = get_config('system','jpeg_quality');
+ if((! $quality) || ($quality > 100))
+ $quality = JPEG_QUALITY;
+ imagejpeg($this->image,$path,$quality);
}
public function imageString() {
ob_start();
- imagejpeg($this->image,NULL,100);
+
+ $quality = get_config('system','jpeg_quality');
+ if((! $quality) || ($quality > 100))
+ $quality = JPEG_QUALITY;
+
+ imagejpeg($this->image,NULL,$quality);
$s = ob_get_contents();
ob_end_clean();
return $s;
diff --git a/include/Scrape.php b/include/Scrape.php
index ff9899252..7fc0c964b 100644
--- a/include/Scrape.php
+++ b/include/Scrape.php
@@ -216,7 +216,7 @@ function scrape_feed($url) {
}
if(stristr($line,'application/rss+xml') || stristr($s,'<rss')) {
$ret['feed_rss'] = $url;
- return ret;
+ return $ret;
}
}
}
@@ -227,17 +227,287 @@ function scrape_feed($url) {
if(! $dom)
return $ret;
+
+ $items = $dom->getElementsByTagName('img');
+
+ // get img elements (twitter)
+
+ if($items) {
+ foreach($items as $item) {
+ $x = $item->getAttribute('id');
+ if($x === 'profile-image') {
+ $ret['photo'] = $item->getAttribute('src');
+ }
+ }
+ }
+
+
+ $head = $dom->getElementsByTagName('base');
+ if($head) {
+ foreach($head as $head0) {
+ $basename = $head0->getAttribute('href');
+ break;
+ }
+ }
+ if(! $basename)
+ $basename = substr($url,0,strrpos($url,'/')) . '/';
+
$items = $dom->getElementsByTagName('link');
- // get Atom link elements
+ // get Atom/RSS link elements, take the first one of either.
- foreach($items as $item) {
- $x = $item->getAttribute('rel');
- if(($x === 'alternate') && ($item->getAttribute('type') === 'application/atom+xml'))
- $ret['feed_atom'] = $item->getAttribute('href');
- if(($x === 'alternate') && ($item->getAttribute('type') === 'application/rss+xml'))
- $ret['feed_rss'] = $item->getAttribute('href');
+ if($items) {
+ foreach($items as $item) {
+ $x = $item->getAttribute('rel');
+ if(($x === 'alternate') && ($item->getAttribute('type') === 'application/atom+xml')) {
+ if(! x($ret,'feed_atom'))
+ $ret['feed_atom'] = $item->getAttribute('href');
+ }
+ if(($x === 'alternate') && ($item->getAttribute('type') === 'application/rss+xml')) {
+ if(! x($ret,'feed_rss'))
+ $ret['feed_rss'] = $item->getAttribute('href');
+ }
+ }
}
+ // Drupal and perhaps others only provide relative URL's. Turn them into absolute.
+
+ if(x($ret,'feed_atom') && (! strstr($ret['feed_atom'],'://')))
+ $ret['feed_atom'] = $basename . $ret['feed_atom'];
+ if(x($ret,'feed_rss') && (! strstr($ret['feed_rss'],'://')))
+ $ret['feed_rss'] = $basename . $ret['feed_rss'];
+
return $ret;
-}} \ No newline at end of file
+}}
+
+
+function probe_url($url) {
+ require_once('include/email.php');
+
+ $result = array();
+
+ if(! $url)
+ return $result;
+
+ $diaspora = false;
+ $email_conversant = false;
+
+ if($url) {
+ $links = lrdd($url);
+
+ if(count($links)) {
+ logger('probe_url: found lrdd links: ' . print_r($links,true), LOGGER_DATA);
+ foreach($links as $link) {
+ if($link['@attributes']['rel'] === NAMESPACE_DFRN)
+ $dfrn = unamp($link['@attributes']['href']);
+ if($link['@attributes']['rel'] === 'salmon')
+ $notify = unamp($link['@attributes']['href']);
+ if($link['@attributes']['rel'] === NAMESPACE_FEED)
+ $poll = unamp($link['@attributes']['href']);
+ if($link['@attributes']['rel'] === 'http://microformats.org/profile/hcard')
+ $hcard = unamp($link['@attributes']['href']);
+ if($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page')
+ $profile = unamp($link['@attributes']['href']);
+ if($link['@attributes']['rel'] === 'http://joindiaspora.com/seed_location')
+ $diaspora = true;
+ }
+
+ // Status.Net can have more than one profile URL. We need to match the profile URL
+ // to a contact on incoming messages to prevent spam, and we won't know which one
+ // to match. So in case of two, one of them is stored as an alias. Only store URL's
+ // and not webfinger user@host aliases. If they've got more than two non-email style
+ // aliases, let's hope we're lucky and get one that matches the feed author-uri because
+ // otherwise we're screwed.
+
+ foreach($links as $link) {
+ if($link['@attributes']['rel'] === 'alias') {
+ if(strpos($link['@attributes']['href'],'@') === false) {
+ if(isset($profile)) {
+ if($link['@attributes']['href'] !== $profile)
+ $alias = unamp($link['@attributes']['href']);
+ }
+ else
+ $profile = unamp($link['@attributes']['href']);
+ }
+ }
+ }
+ }
+ else {
+
+ // Check email
+
+ $orig_url = $url;
+ if((strpos($orig_url,'@')) && validate_email($orig_url)) {
+ $x = q("SELECT `prvkey` FROM `user` WHERE `uid` = %d LIMIT 1",
+ intval(local_user())
+ );
+ $r = q("SELECT * FROM `mailacct` WHERE `uid` = %d AND `server` != '' LIMIT 1",
+ intval(local_user())
+ );
+ if(count($x) && count($r)) {
+ $mailbox = construct_mailbox_name($r[0]);
+ $password = '';
+ openssl_private_decrypt(hex2bin($r[0]['pass']),$password,$x[0]['prvkey']);
+ $mbox = email_connect($mailbox,$r[0]['user'],$password);
+ unset($password);
+ }
+ if($mbox) {
+ $msgs = email_poll($mbox,$orig_url);
+ if(count($msgs)) {
+ $addr = $orig_url;
+ $network = NETWORK_MAIL;
+ $name = substr($url,0,strpos($url,'@'));
+ $profile = 'http://' . substr($url,strpos($url,'@')+1);
+ // fix nick character range
+ $vcard = array('fn' => $name, 'nick' => $name, 'photo' => gravatar_img($url));
+ $notify = 'smtp ' . random_string();
+ $poll = 'email ' . random_string();
+ $priority = 0;
+ $x = email_msg_meta($mbox,$msgs[0]);
+ if(stristr($x->from,$orig_url))
+ $adr = imap_rfc822_parse_adrlist($x->from,'');
+ elseif(stristr($x->to,$orig_url))
+ $adr = imap_rfc822_parse_adrlist($x->to,'');
+ if(isset($adr) && strlen($adr[0]->personal))
+ $vcard['fn'] = notags($adr[0]->personal);
+ }
+ imap_close($mbox);
+ }
+ }
+ }
+ }
+
+ if(strlen($dfrn)) {
+ $ret = scrape_dfrn($dfrn);
+ if(is_array($ret) && x($ret,'dfrn-request')) {
+ $network = NETWORK_DFRN;
+ $request = $ret['dfrn-request'];
+ $confirm = $ret['dfrn-confirm'];
+ $notify = $ret['dfrn-notify'];
+ $poll = $ret['dfrn-poll'];
+ }
+ }
+
+ if($network !== NETWORK_DFRN && $network !== NETWORK_MAIL) {
+ $network = NETWORK_OSTATUS;
+ $priority = 0;
+
+ if($hcard) {
+ $vcard = scrape_vcard($hcard);
+
+ // Google doesn't use absolute url in profile photos
+
+ if((x($vcard,'photo')) && substr($vcard['photo'],0,1) == '/') {
+ $h = @parse_url($hcard);
+ if($h)
+ $vcard['photo'] = $h['scheme'] . '://' . $h['host'] . $vcard['photo'];
+ }
+
+ logger('probe_url: scrape_vcard: ' . print_r($vcard,true), LOGGER_DATA);
+ }
+
+ if(! $profile) {
+ if($diaspora)
+ $profile = $hcard;
+ else
+ $profile = $url;
+ }
+
+ if(! x($vcard,'fn'))
+ if(x($vcard,'nick'))
+ $vcard['fn'] = $vcard['nick'];
+
+ if((! isset($vcard)) && (! $poll)) {
+
+ $ret = scrape_feed($url);
+ logger('probe_url: scrape_feed returns: ' . print_r($ret,true), LOGGER_DATA);
+ if(count($ret) && ($ret['feed_atom'] || $ret['feed_rss'])) {
+ $poll = ((x($ret,'feed_atom')) ? unamp($ret['feed_atom']) : unamp($ret['feed_rss']));
+ $vcard = array();
+ if(x($ret,'photo'))
+ $vcard['photo'] = $ret['photo'];
+ require_once('simplepie/simplepie.inc');
+ $feed = new SimplePie();
+ $xml = fetch_url($poll);
+
+ $feed->set_raw_data($xml);
+
+ $feed->init();
+
+ if(! x($vcard,'photo'))
+ $vcard['photo'] = $feed->get_image_url();
+ $author = $feed->get_author();
+ if($author) {
+ $vcard['fn'] = unxmlify(trim($author->get_name()));
+ if(! $vcard['fn'])
+ $vcard['fn'] = trim(unxmlify($author->get_email()));
+ if(strpos($vcard['fn'],'@') !== false)
+ $vcard['fn'] = substr($vcard['fn'],0,strpos($vcard['fn'],'@'));
+ $vcard['nick'] = strtolower(notags(unxmlify($vcard['fn'])));
+ if(strpos($vcard['nick'],' '))
+ $vcard['nick'] = trim(substr($vcard['nick'],0,strpos($vcard['nick'],' ')));
+ $email = unxmlify($author->get_email());
+ }
+ else {
+ $item = $feed->get_item(0);
+ if($item) {
+ $author = $item->get_author();
+ if($author) {
+ $vcard['fn'] = trim(unxmlify($author->get_name()));
+ if(! $vcard['fn'])
+ $vcard['fn'] = trim(unxmlify($author->get_email()));
+ if(strpos($vcard['fn'],'@') !== false)
+ $vcard['fn'] = substr($vcard['fn'],0,strpos($vcard['fn'],'@'));
+ $vcard['nick'] = strtolower(unxmlify($vcard['fn']));
+ if(strpos($vcard['nick'],' '))
+ $vcard['nick'] = trim(substr($vcard['nick'],0,strpos($vcard['nick'],' ')));
+ $email = unxmlify($author->get_email());
+ }
+ if(! $vcard['photo']) {
+ $rawmedia = $item->get_item_tags('http://search.yahoo.com/mrss/','thumbnail');
+ if($rawmedia && $rawmedia[0]['attribs']['']['url'])
+ $vcard['photo'] = unxmlify($rawmedia[0]['attribs']['']['url']);
+ }
+ }
+ }
+ if((! $vcard['photo']) && strlen($email))
+ $vcard['photo'] = gravatar_img($email);
+ if($poll === $profile)
+ $lnk = $feed->get_permalink();
+ if(isset($lnk) && strlen($lnk))
+ $profile = $lnk;
+ if(! (x($vcard,'fn')))
+ $vcard['fn'] = notags($feed->get_title());
+ if(! (x($vcard,'fn')))
+ $vcard['fn'] = notags($feed->get_description());
+ $network = 'feed';
+ $priority = 2;
+ }
+ }
+ }
+
+ if(! x($vcard,'photo')) {
+ $a = get_app();
+ $vcard['photo'] = $a->get_baseurl() . '/images/default-profile.jpg' ;
+ }
+ $vcard['fn'] = notags($vcard['fn']);
+ $vcard['nick'] = notags($vcard['nick']);
+
+
+ $result['name'] = $vcard['fn'];
+ $result['nick'] = $vcard['nick'];
+ $result['url'] = $profile;
+ $result['addr'] = $addr;
+ $result['notify'] = $notify;
+ $result['poll'] = $poll;
+ $result['request'] = $request;
+ $result['confirm'] = $confirm;
+ $result['photo'] = $vcard['photo'];
+ $result['priority'] = $priority;
+ $result['network'] = $network;
+ $result['alias'] = $alias;
+
+ logger('probe_url: ' . print_r($result,true), LOGGER_DEBUG);
+
+ return $result;
+}
diff --git a/include/acl_selectors.php b/include/acl_selectors.php
index fa700818f..b1bcf5108 100644
--- a/include/acl_selectors.php
+++ b/include/acl_selectors.php
@@ -48,7 +48,7 @@ function contact_select($selname, $selclass, $preselected = false, $size = 4, $p
$o = '';
- // When used for private messages, we limit correspondence to mutual friends and the selector
+ // When used for private messages, we limit correspondence to mutual DFRN/Friendika friends and the selector
// to one recipient. By default our selector allows multiple selects amongst all contacts.
$sql_extra = '';
@@ -57,9 +57,12 @@ function contact_select($selname, $selclass, $preselected = false, $size = 4, $p
$sql_extra .= sprintf(" AND `rel` = %d ", intval(REL_BUD));
}
- if($privmail || $privatenet) {
+ if($privmail) {
$sql_extra .= " AND `network` IN ( 'dfrn' ) ";
- }
+ }
+ elseif($privatenet) {
+ $sql_extra .= " AND `network` IN ( 'dfrn', 'mail', 'face' ) ";
+ }
if($privmail)
$o .= "<select name=\"$selname\" id=\"$selclass\" class=\"$selclass\" size=\"$size\" >\r\n";
@@ -80,8 +83,6 @@ function contact_select($selname, $selclass, $preselected = false, $size = 4, $p
call_hooks($a->module . '_pre_' . $selname, $arr);
-
-
if(count($r)) {
foreach($r as $rr) {
if((is_array($preselected)) && in_array($rr['id'], $preselected))
@@ -129,7 +130,7 @@ function populate_acl($user = null,$celeb = false) {
$o = '';
$o .= '<div id="acl-wrapper">';
$o .= '<div id="acl-permit-outer-wrapper">';
- $o .= '<div id="acl-permit-text">' . t('Visible To:') . '</div>';
+ $o .= '<div id="acl-permit-text">' . t('Visible To:') . '</div><div id="jot-public">' . t('everybody') . '</div>';
$o .= '<div id="acl-permit-text-end"></div>';
$o .= '<div id="acl-permit-wrapper">';
$o .= '<div id="group_allow_wrapper">';
diff --git a/include/api.php b/include/api.php
new file mode 100644
index 000000000..84cb7b38f
--- /dev/null
+++ b/include/api.php
@@ -0,0 +1,431 @@
+<?php
+ require_once("bbcode.php");
+ require_once("datetime.php");
+
+ /*
+ * Twitter-Like API
+ *
+ */
+
+ $API = Array();
+
+
+
+ function api_date($str){
+ //Wed May 23 06:01:13 +0000 2007
+ return datetime_convert('UTC', 'UTC', $str, "D M d h:i:s +0000 Y" );
+ }
+
+
+ function api_register_func($path, $func, $auth=false){
+ global $API;
+ $API[$path] = array('func'=>$func,
+ 'auth'=>$auth);
+ }
+
+ /**
+ * Simple HTTP Login
+ */
+ function api_login(&$a){
+ if (!isset($_SERVER['PHP_AUTH_USER'])) {
+ header('WWW-Authenticate: Basic realm="Friendika"');
+ header('HTTP/1.0 401 Unauthorized');
+ die('This api require login');
+ }
+
+ $user = $_SERVER['PHP_AUTH_USER'];
+ $encrypted = hash('whirlpool',trim($_SERVER['PHP_AUTH_PW']));
+
+
+ /**
+ * next code from mod/auth.php. needs better solution
+ */
+
+ // process normal login request
+
+ $r = q("SELECT * FROM `user` WHERE ( `email` = '%s' OR `nickname` = '%s' )
+ AND `password` = '%s' AND `blocked` = 0 AND `verified` = 1 LIMIT 1",
+ dbesc(trim($user)),
+ dbesc(trim($user)),
+ dbesc($encrypted)
+ );
+ if(count($r)){
+ $record = $r[0];
+ } else {
+ header('WWW-Authenticate: Basic realm="Friendika"');
+ header('HTTP/1.0 401 Unauthorized');
+ die('This api require login');
+ }
+ $_SESSION['uid'] = $record['uid'];
+ $_SESSION['theme'] = $record['theme'];
+ $_SESSION['authenticated'] = 1;
+ $_SESSION['page_flags'] = $record['page-flags'];
+ $_SESSION['my_url'] = $a->get_baseurl() . '/profile/' . $record['nickname'];
+ $_SESSION['addr'] = $_SERVER['REMOTE_ADDR'];
+
+ //notice( t("Welcome back ") . $record['username'] . EOL);
+ $a->user = $record;
+
+ if(strlen($a->user['timezone'])) {
+ date_default_timezone_set($a->user['timezone']);
+ $a->timezone = $a->user['timezone'];
+ }
+
+ $r = q("SELECT * FROM `contact` WHERE `uid` = %s AND `self` = 1 LIMIT 1",
+ intval($_SESSION['uid']));
+ if(count($r)) {
+ $a->contact = $r[0];
+ $a->cid = $r[0]['id'];
+ $_SESSION['cid'] = $a->cid;
+ }
+ q("UPDATE `user` SET `login_date` = '%s' WHERE `uid` = %d LIMIT 1",
+ dbesc(datetime_convert()),
+ intval($_SESSION['uid'])
+ );
+
+ call_hooks('logged_in', $a->user);
+
+ header('X-Account-Management-Status: active; name="' . $a->user['username'] . '"; id="' . $a->user['nickname'] .'"');
+ }
+
+ /**************************
+ * MAIN API ENTRY POINT *
+ **************************/
+ function api_call(&$a){
+ GLOBAL $API;
+ foreach ($API as $p=>$info){
+ if (strpos($a->query_string, $p)===0){
+ #unset($_SERVER['PHP_AUTH_USER']);
+ if ($info['auth']===true && local_user()===false) {
+ api_login($a);
+ }
+
+ $type="json";
+ if (strpos($a->query_string, ".xml")>0) $type="xml";
+ if (strpos($a->query_string, ".json")>0) $type="json";
+ if (strpos($a->query_string, ".rss")>0) $type="rss";
+ if (strpos($a->query_string, ".atom")>0) $type="atom";
+
+ $r = call_user_func($info['func'], $a, $type);
+ if ($r===false) return;
+
+ switch($type){
+ case "xml":
+ $r = mb_convert_encoding($r, "UTF-8",mb_detect_encoding($r));
+ header ("Content-Type: text/xml");
+ return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
+ break;
+ case "json":
+ header ("Content-Type: application/json");
+ return json_encode($r);
+ break;
+ case "rss":
+ header ("Content-Type: application/rss+xml");
+ return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
+ break;
+ case "atom":
+ #header ("Content-Type: application/atom+xml");
+ return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
+ break;
+
+ }
+ //echo "<pre>"; var_dump($r); die();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * RSS extra info
+ */
+ function api_rss_extra(&$a, $arr, $user_info){
+ if (is_null($user_info)) $user_info = api_get_user($a);
+ $arr['$rss'] = array(
+ 'alternate' => $user_info['url'],
+ 'self' => $a->get_baseurl(). "/". $a->query_string,
+ 'updated' => api_date(null),
+ 'language' => $user_info['language'],
+ 'logo' => $a->get_baseurl()."/images/friendika-32.png",
+ );
+
+ return $arr;
+ }
+
+ /**
+ * Returns user info array.
+ */
+ function api_get_user(&$a){
+ $user = null;
+ $extra_query = "";
+ if(x($_GET, 'user_id')) {
+ $user = intval($_GET['user_id']);
+ $extra_query = "AND `contact`.`id` = %d ";
+ }
+ if(x($_GET, 'screen_name')) {
+ $user = dbesc($_GET['screen_name']);
+ $extra_query = "AND `contact`.`nick` = '%s' ";
+ }
+
+ if ($user===null){
+ list($user, $null) = explode(".",$a->argv[3]);
+ if(is_numeric($user)){
+ $user = intval($user);
+ $extra_query = "AND `contact`.`id` = %d ";
+ } else {
+ $user = dbesc($user);
+ $extra_query = "AND `contact`.`nick` = '%s' ";
+ }
+ }
+
+ if ($user==='') {
+ if (local_user()===false) {
+ api_login($a); return False;
+ } else {
+ $user = $_SESSION['uid'];
+ $extra_query = "AND `user`.`uid` = %d ";
+ }
+
+ }
+
+
+ // user info
+ $uinfo = q("SELECT *, `contact`.`id` as `cid` FROM `user`, `contact`
+ WHERE `user`.`uid`=`contact`.`uid` AND `contact`.`self`=1
+ $extra_query",
+ $user
+ );
+ if (count($uinfo)==0) {
+ return False;
+ }
+
+ // count public wall messages
+ $r = q("SELECT COUNT(`id`) as `count` FROM `item`
+ WHERE `uid` = %d
+ AND `type`='wall'
+ AND `allow_cid`='' AND `allow_gid`='' AND `deny_cid`='' AND `deny_gid`=''",
+ intval($uinfo[0]['uid'])
+ );
+ $countitms = $r[0]['count'];
+
+ // count friends
+ $r = q("SELECT COUNT(`id`) as `count` FROM `contact`
+ WHERE `uid` = %d
+ AND `self`=0 AND `blocked`=0",
+ intval($uinfo[0]['uid'])
+ );
+ $countfriends = $r[0]['count'];
+
+
+ $ret = Array(
+ 'id' => $uinfo[0]['cid'],
+ 'name' => $uinfo[0]['username'],
+ 'screen_name' => $uinfo[0]['nickname'],
+ 'location' => $uinfo[0]['default-location'],
+ 'profile_image_url' => $uinfo[0]['micro'],
+ 'url' => $uinfo[0]['url'],
+ 'protected' => false, #
+ 'friends_count' => $countfriends,
+ 'created_at' => api_date($uinfo[0]['created']),
+ 'utc_offset' => 0, #XXX: fix me
+ 'time_zone' => $uinfo[0]['timezone'],
+ 'geo_enabled' => false,
+ 'statuses_count' => $countitms, #XXX: fix me
+ 'lang' => 'en', #XXX: fix me
+ 'description' => '',
+ 'followers_count' => $countfriends, #XXX: fix me
+ 'lang' => 'en', #XXX: fix me
+ 'favourites_count' => 0,
+ 'contributors_enabled' => false,
+ 'follow_request_sent' => false,
+ 'profile_background_color' => 'cfe8f6',
+ 'profile_text_color' => '000000',
+ 'profile_link_color' => 'FF8500',
+ 'profile_sidebar_fill_color' =>'AD0066',
+ 'profile_sidebar_border_color' => 'AD0066',
+ 'profile_background_image_url' => '',
+ 'profile_background_tile' => false,
+ 'profile_use_background_image' => false,
+ 'notifications' => false,
+ 'verified' => true, #XXX: fix me
+ 'followers' => '', #XXX: fix me
+ #'status' => null
+ );
+
+ return $ret;
+
+ }
+
+ /**
+ * apply xmlify() to all values of array $val, recursively
+ */
+ function api_xmlify($val){
+ if (is_bool($val)) return $val?"true":"false";
+ if (is_array($val)) return array_map('api_xmlify', $val);
+ return xmlify($val);
+ }
+
+ /**
+ * load api $templatename for $type and replace $data array
+ */
+ function api_apply_template($templatename, $type, $data){
+ switch($type){
+ case "rss":
+ case "atom":
+ case "xml":
+ $data = api_xmlify($data);
+ $tpl = get_markup_template("api_".$templatename."_".$type.".tpl");
+ $ret = replace_macros($tpl, $data);
+ break;
+ case "json":
+ $ret = $data;
+ break;
+ }
+ return $ret;
+ }
+
+ /**
+ ** TWITTER API
+ */
+
+ /**
+ * Returns an HTTP 200 OK response code and a representation of the requesting user if authentication was successful;
+ * returns a 401 status code and an error message if not.
+ * http://developer.twitter.com/doc/get/account/verify_credentials
+ */
+ function api_account_verify_credentials(&$a, $type){
+ if (local_user()===false) return false;
+ $user_info = api_get_user($a);
+
+ return api_apply_template("user", $type, array('$user' => $user_info));
+
+ }
+ api_register_func('api/account/verify_credentials','api_account_verify_credentials', true);
+
+
+
+ /**
+ * Returns extended information of a given user, specified by ID or screen name as per the required id parameter.
+ * The author's most recent status will be returned inline.
+ * http://developer.twitter.com/doc/get/users/show
+ */
+ function api_users_show(&$a, $type){
+ $user_info = api_get_user($a);
+ // get last public wall message
+ $lastwall = q("SELECT `item`.*, `i`.`contact-id` as `reply_uid`, `i`.`nick` as `reply_author`
+ FROM `item`, `contact`,
+ (SELECT `item`.`id`, `item`.`contact-id`, `contact`.`nick` FROM `item`,`contact` WHERE `contact`.`id`=`item`.`contact-id`) as `i`
+ WHERE `item`.`contact-id` = %d
+ AND `i`.`id` = `item`.`parent`
+ AND `contact`.`id`=`item`.`contact-id` AND `contact`.`self`=1
+ AND `type`!='activity'
+ AND `item`.`allow_cid`='' AND `item`.`allow_gid`='' AND `item`.`deny_cid`='' AND `item`.`deny_gid`=''
+ ORDER BY `created` DESC
+ LIMIT 1",
+ intval($user_info['id'])
+ );
+
+ if (count($lastwall)>0){
+ $lastwall = $lastwall[0];
+
+ $in_reply_to_status_id = '';
+ $in_reply_to_user_id = '';
+ $in_reply_to_screen_name = '';
+ if ($lastwall['parent']!=$lastwall['id']) {
+ $in_reply_to_status_id=$lastwall['parent'];
+ $in_reply_to_user_id = $lastwall['reply_uid'];
+ $in_reply_to_screen_name = $lastwall['reply_author'];
+ }
+ $user_info['status'] = array(
+ 'created_at' => api_date($lastwall['created']),
+ 'id' => $lastwall['contact-id'],
+ 'text' => strip_tags(bbcode($lastwall['body'])),
+ 'source' => 'web',
+ 'truncated' => false,
+ 'in_reply_to_status_id' => $in_reply_to_status_id,
+ 'in_reply_to_user_id' => $in_reply_to_user_id,
+ 'favorited' => false,
+ 'in_reply_to_screen_name' => $in_reply_to_screen_name,
+ 'geo' => '',
+ 'coordinates' => $lastwall['coord'],
+ 'place' => $lastwall['location'],
+ 'contributors' => ''
+ );
+ }
+ return api_apply_template("user", $type, array('$user' => $user_info));
+
+ }
+ api_register_func('api/users/show','api_users_show');
+
+ /**
+ *
+ * http://developer.twitter.com/doc/get/statuses/home_timeline
+ *
+ * TODO: Optional parameters
+ * TODO: Add reply info
+ */
+ function api_statuses_home_timeline(&$a, $type){
+ if (local_user()===false) return false;
+
+ $user_info = api_get_user($a);
+
+ // get last newtork messages
+ $sql_extra = " AND `item`.`parent` IN ( SELECT `parent` FROM `item` WHERE `id` = `parent` ) ";
+
+ $r = q("SELECT `item`.*, `item`.`id` AS `item_id`,
+ `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`,
+ `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
+ `contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid`
+ FROM `item`, `contact`, `user`
+ WHERE `item`.`contact-id` = %d AND `user`.`uid` = `item`.`uid`
+ AND `item`.`visible` = 1 AND `item`.`deleted` = 0
+ AND `contact`.`id` = `item`.`contact-id`
+ AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
+ $sql_extra
+ ORDER BY `item`.`created` DESC LIMIT %d ,%d ",
+ intval($user_info['id']),
+ 0,20
+ );
+ $ret = Array();
+
+ foreach($r as $item) {
+ $status = array(
+ 'created_at'=> api_date($item['created']),
+ 'id' => $item['id'],
+ 'text' => strip_tags(bbcode($item['body'])),
+ 'html' => bbcode($item['body']),
+ 'source' => 'web',
+ 'url' => ($item['plink']!=''?$item['plink']:$item['author-link']),
+ 'truncated' => False,
+ 'in_reply_to_status_id' => ($item['parent']!=$item['id']?$item['id']:''),
+ 'in_reply_to_user_id' => '',
+ 'favorited' => false,
+ 'in_reply_to_screen_name' => '',
+ 'geo' => '',
+ 'coordinates' => $item['coord'],
+ 'place' => $item['location'],
+ 'contributors' => '',
+ 'annotations' => '',
+ 'entities' => '',
+ 'user' => $user_info,
+ 'objecttype' => $item['object-type'],
+ 'verb' => $item['verb'],
+ 'self' => $a->get_baseurl()."/api/statuses/show/".$ite['id'].".".$type,
+ 'edit' => $a->get_baseurl()."/api/statuses/show/".$ite['id'].".".$type,
+ );
+ $ret[]=$status;
+ };
+
+ $data = array('$statuses' => $ret);
+ switch($type){
+ case "atom":
+ case "rss":
+ $data = api_rss_extra($a, $data, $user_info);
+ }
+
+ return api_apply_template("timeline", $type, $data);
+ }
+ api_register_func('api/statuses/home_timeline','api_statuses_home_timeline', true);
+ api_register_func('api/statuses/friends_timeline','api_statuses_home_timeline', true);
+ api_register_func('api/statuses/user_timeline','api_statuses_home_timeline', true);
+ # TODO: user_timeline should be profile view
+
diff --git a/include/auth.php b/include/auth.php
index e8cee3918..1c430406e 100644
--- a/include/auth.php
+++ b/include/auth.php
@@ -28,6 +28,15 @@ if((isset($_SESSION)) && (x($_SESSION,'authenticated')) && ((! (x($_POST,'auth-p
goaway($a->get_baseurl());
}
+ if(x($_SESSION,'visitor_id') && (! x($_SESSION,'uid'))) {
+ $r = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1",
+ intval($_SESSION['visitor_id'])
+ );
+ if(count($r)) {
+ $a->contact = $r[0];
+ }
+ }
+
if(x($_SESSION,'uid')) {
// already logged in user returning
@@ -191,9 +200,17 @@ else {
$_SESSION['my_url'] = $a->get_baseurl() . '/profile/' . $record['nickname'];
$_SESSION['addr'] = $_SERVER['REMOTE_ADDR'];
- notice( t("Welcome back ") . $record['username'] . EOL);
$a->user = $record;
+ if($a->user['login_date'] === '0000-00-00 00:00:00') {
+ $_SESSION['return_url'] = 'profile_photo/new';
+ $a->module = 'profile_photo';
+ notice( t("Welcome ") . $a->user['username'] . EOL);
+ notice( t('Please upload a profile photo.') . EOL);
+ }
+ else
+ notice( t("Welcome back ") . $a->user['username'] . EOL);
+
if(strlen($a->user['timezone'])) {
date_default_timezone_set($a->user['timezone']);
$a->timezone = $a->user['timezone'];
@@ -214,6 +231,8 @@ else {
$a->cid = $r[0]['id'];
$_SESSION['cid'] = $a->cid;
}
+
+
q("UPDATE `user` SET `login_date` = '%s' WHERE `uid` = %d LIMIT 1",
dbesc(datetime_convert()),
intval($_SESSION['uid'])
diff --git a/include/bbcode.php b/include/bbcode.php
index 978b4af69..195fc9181 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -3,7 +3,7 @@ require_once("include/oembed.php");
// BBcode 2 HTML was written by WAY2WEB.net
// extended to work with Mistpark/Friendika - Mike Macgirvin
-function bbcode($Text) {
+function bbcode($Text,$preserve_nl = false) {
// Replace any html brackets with HTML Entities to prevent executing HTML or script
// Don't use strip_tags here because it breaks [url] search by replacing & with amp
@@ -12,7 +12,10 @@ function bbcode($Text) {
$Text = str_replace(">", "&gt;", $Text);
// Convert new line chars to html <br /> tags
+
$Text = nl2br($Text);
+ if($preserve_nl)
+ $Text = str_replace(array("\n","\r"), array('',''),$Text);
// Set up the parameters for a URL search string
$URLSearchString = "^\[\]";
@@ -22,7 +25,7 @@ function bbcode($Text) {
// Perform URL Search
- $Text = preg_replace("/([^\]\=]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\.\=\_\~\#\'\%\$\!\+]+)/", ' <a href="$2" target="external-link">$2</a>', $Text);
+ $Text = preg_replace("/([^\]\=]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\.\=\_\~\#\'\%\$\!\+\,]+)/", ' <a href="$2" target="external-link">$2</a>', $Text);
$Text = preg_replace("/\[url\]([$URLSearchString]*)\[\/url\]/", '<a href="$1" target="external-link">$1</a>', $Text);
$Text = preg_replace("(\[url\=([$URLSearchString]*)\](.+?)\[/url\])", '<a href="$1" target="external-link">$2</a>', $Text);
@@ -77,7 +80,7 @@ function bbcode($Text) {
// Images
// [img]pathtoimage[/img]
- $Text = preg_replace("/\[img\](.+?)\[\/img\]/", '<img src="$1">', $Text);
+ $Text = preg_replace("/\[img\](.+?)\[\/img\]/", '<img src="$1" alt="' . t('Image/photo') . '" />', $Text);
// html5 video and audio
@@ -90,8 +93,12 @@ function bbcode($Text) {
$Text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.+?)\[\/img\]/", '<img src="$3" height="$2" width="$1">', $Text);
// Youtube extensions
- $Text = preg_replace("/\[youtube\]http:\/\/www.youtube.com\/watch\?v\=(.+?)\[\/youtube\]/",'[youtube]$1[/youtube]',$Text);
- $Text = preg_replace("/\[youtube\](.+?)\[\/youtube\]/", '<object width="425" height="350" type="application/x-shockwave-flash" data="http://www.youtube.com/v/$1" ><param name="movie" value="http://www.youtube.com/v/$1"></param><!--[if IE]><embed src="http://www.youtube.com/v/$1" type="application/x-shockwave-flash" width="425" height="350" /><![endif]--></object>', $Text);
+ $Text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/watch\?v\=(.+?)\[\/youtube\]/",'[youtube]$1[/youtube]',$Text);
+ $Text = preg_replace("/\[youtube\]https?:\/\/youtu.be\/(.+?)\[\/youtube\]/",'[youtube]$1[/youtube]',$Text);
+
+ $Text = preg_replace("/\[youtube\](.+?)\[\/youtube\]/", '<iframe width="425" height="349" src="http://www.youtube.com/embed/$1" frameborder="0" allowfullscreen></iframe>', $Text);
+
+// $Text = preg_replace("/\[youtube\](.+?)\[\/youtube\]/", '<object width="425" height="350" type="application/x-shockwave-flash" data="http://www.youtube.com/v/$1" ><param name="movie" value="http://www.youtube.com/v/$1"></param><!--[if IE]><embed src="http://www.youtube.com/v/$1" type="application/x-shockwave-flash" width="425" height="350" /><![endif]--></object>', $Text);
// oembed tag
$Text = oembed_bbcode2html($Text);
diff --git a/include/conversation.php b/include/conversation.php
new file mode 100644
index 000000000..5f761ccf0
--- /dev/null
+++ b/include/conversation.php
@@ -0,0 +1,755 @@
+<?php
+
+/**
+ * Render actions localized
+ */
+function localize_item(&$item){
+
+ if ($item['verb']=="http://activitystrea.ms/schema/1.0/like" ||
+ $item['verb']=="http://activitystrea.ms/schema/1.0/dislike"){
+
+ $r = q("SELECT * from `item`,`contact` WHERE
+ `item`.`contact-id`=`contact`.`id` AND `item`.`uri`='%s';",
+ dbesc($item['parent-uri']));
+ if(count($r)==0) return;
+ $obj=$r[0];
+
+ $author = '[url=' . $item['author-link'] . ']' . $item['author-name'] . '[/url]';
+ $objauthor = '[url=' . $obj['author-link'] . ']' . $obj['author-name'] . '[/url]';
+
+ $post_type = (($obj['resource-id']) ? t('photo') : t('status'));
+ $plink = '[url=' . $obj['plink'] . ']' . $post_type . '[/url]';
+
+ switch($item['verb']){
+ case "http://activitystrea.ms/schema/1.0/like":
+ $bodyverb = t('%1$s likes %2$s\'s %3$s');
+ break;
+ case "http://activitystrea.ms/schema/1.0/dislike":
+ $bodyverb = t('%1$s doesn\'t like %2$s\'s %3$s');
+ break;
+ }
+ $item['body'] = sprintf($bodyverb, $author, $objauthor, $plink);
+
+ }
+ if ($item['verb']=='http://activitystrea.ms/schema/1.0/make-friend'){
+
+ if ($item['object-type']=="" || $item['object-type']!='http://activitystrea.ms/schema/1.0/person') return;
+
+ $Aname = $item['author-name'];
+ $Alink = $item['author-link'];
+
+ $xmlhead="<"."?xml version='1.0' encoding='UTF-8' ?".">";
+
+ $obj = parse_xml_string($xmlhead.$item['object']);
+ $links = parse_xml_string($xmlhead."<links>".unxmlify($obj->link)."</links>");
+
+ $Bname = $obj->title;
+ $Blink = ""; $Bphoto = "";
+ foreach ($links->link as $l){
+ $atts = $l->attributes();
+ switch($atts['rel']){
+ case "alternate": $Blink = $atts['href'];
+ case "photo": $Bphoto = $atts['href'];
+ }
+
+ }
+
+ $A = '[url=' . $Alink . ']' . $Aname . '[/url]';
+ $B = '[url=' . $Blink . ']' . $Bname . '[/url]';
+ if ($Bphoto!="") $Bphoto = '[url=' . $Blink . '][img]' . $Bphoto . '[/img][/url]';
+
+ $item['body'] = sprintf( t('%1$s is now friends with %2$s'), $A, $B)."\n\n\n".$Bphoto;
+
+ }
+
+}
+
+/**
+ * "Render" a conversation or list of items for HTML display.
+ * There are two major forms of display:
+ * - Sequential or unthreaded ("New Item View" or search results)
+ * - conversation view
+ * The $mode parameter decides between the various renderings and also
+ * figures out how to determine page owner and other contextual items
+ * that are based on unique features of the calling module.
+ *
+ */
+function conversation(&$a, $items, $mode, $update) {
+
+ require_once('bbcode.php');
+
+ $profile_owner = 0;
+ $page_writeable = false;
+
+ if($mode === 'network') {
+ $profile_owner = local_user();
+ $page_writeable = true;
+ }
+
+ if($mode === 'profile') {
+ $profile_owner = $a->profile['profile_uid'];
+ $page_writeable = can_write_wall($a,$profile_owner);
+ }
+
+ if($mode === 'notes') {
+ $profile_owner = $a->profile['profile_uid'];
+ $page_writeable = true;
+ }
+
+ if($mode === 'display') {
+ $profile_owner = $a->profile['uid'];
+ $page_writeable = can_write_wall($a,$profile_owner);
+ }
+
+ if($update)
+ $return_url = $_SESSION['return_url'];
+ else
+ $return_url = $_SESSION['return_url'] = $a->cmd;
+
+ load_contact_links(local_user());
+
+
+ $cmnt_tpl = get_markup_template('comment_item.tpl');
+ $like_tpl = get_markup_template('like.tpl');
+ $noshare_tpl = get_markup_template('like_noshare.tpl');
+ $tpl = get_markup_template('wall_item.tpl');
+ $wallwall = get_markup_template('wallwall_item.tpl');
+
+ $alike = array();
+ $dlike = array();
+
+ if(count($items)) {
+
+ if($mode === 'network-new' || $mode === 'search') {
+
+ // "New Item View" on network page or search page results
+ // - just loop through the items and format them minimally for display
+
+ $tpl = get_markup_template('search_item.tpl');
+ $droptpl = get_markup_template('wall_fake_drop.tpl');
+
+ foreach($items as $item) {
+
+ $comment = '';
+ $owner_url = '';
+ $owner_photo = '';
+ $owner_name = '';
+ $sparkle = '';
+
+ if($mode === 'search') {
+ if(((activity_match($item['verb'],ACTIVITY_LIKE)) || (activity_match($item['verb'],ACTIVITY_DISLIKE)))
+ && ($item['id'] != $item['parent']))
+ continue;
+ $nickname = $item['nickname'];
+ }
+ else
+ $nickname = $a->user['nickname'];
+
+ $profile_name = ((strlen($item['author-name'])) ? $item['author-name'] : $item['name']);
+
+ $sp = false;
+ $profile_link = best_link_url($item,$sp);
+ if($sp)
+ $sparkle = ' sparkle';
+ if($profile_link === 'mailbox')
+ $profile_link = '';
+
+
+ $normalised = normalise_link((strlen($item['author-link'])) ? $item['author-link'] : $item['url']);
+ if(($normalised != 'mailbox') && (x($a->contacts[$normalised])))
+ $profile_avatar = $a->contacts[$normalised]['thumb'];
+ else
+ $profile_avatar = ((strlen($item['author-avatar'])) ? $item['author-avatar'] : $item['thumb']);
+
+ $location = (($item['location']) ? '<a target="map" title="' . $item['location'] . '" href="http://maps.google.com/?q=' . urlencode($item['location']) . '">' . $item['location'] . '</a>' : '');
+ $coord = (($item['coord']) ? '<a target="map" title="' . $item['coord'] . '" href="http://maps.google.com/?q=' . urlencode($item['coord']) . '">' . $item['coord'] . '</a>' : '');
+ if($coord) {
+ if($location)
+ $location .= '<br /><span class="smalltext">(' . $coord . ')</span>';
+ else
+ $location = '<span class="smalltext">' . $coord . '</span>';
+ }
+
+ $drop = '';
+ $dropping = false;
+
+ if((intval($item['contact-id']) && $item['contact-id'] == remote_user()) || ($item['uid'] == local_user()))
+ $dropping = true;
+
+ $drop = replace_macros((($dropping)? $droptpl : $fakedrop), array('$id' => $item['id'], '$delete' => t('Delete')));
+
+ //
+ localize_item($item);
+
+ $drop = replace_macros($droptpl,array('$id' => $item['id']));
+ $lock = '<div class="wall-item-lock"></div>';
+
+ $o .= replace_macros($tpl,array(
+ '$id' => $item['item_id'],
+ '$linktitle' => sprintf( t('View %s\'s profile'), $profile_name),
+ '$profile_url' => $profile_link,
+ '$item_photo_menu' => item_photo_menu($item),
+ '$name' => $profile_name,
+ '$sparkle' => $sparkle,
+ '$lock' => $lock,
+ '$thumb' => $profile_avatar,
+ '$title' => $item['title'],
+ '$body' => smilies(bbcode($item['body'])),
+ '$ago' => relative_date($item['created']),
+ '$location' => $location,
+ '$indent' => '',
+ '$owner_url' => $owner_url,
+ '$owner_photo' => $owner_photo,
+ '$owner_name' => $owner_name,
+ '$drop' => $drop,
+ '$conv' => '<a href="' . $a->get_baseurl() . '/display/' . $nickname . '/' . $item['id'] . '">' . t('View in context') . '</a>'
+ ));
+
+ }
+
+ return $o;
+ }
+
+
+
+
+ // Normal View
+
+
+ // Figure out how many comments each parent has
+ // (Comments all have gravity of 6)
+ // Store the result in the $comments array
+
+ $comments = array();
+ foreach($items as $item) {
+ if((intval($item['gravity']) == 6) && ($item['id'] != $item['parent'])) {
+ if(! x($comments,$item['parent']))
+ $comments[$item['parent']] = 1;
+ else
+ $comments[$item['parent']] += 1;
+ }
+ }
+
+ // map all the like/dislike activities for each parent item
+ // Store these in the $alike and $dlike arrays
+
+ foreach($items as $item) {
+ like_puller($a,$item,$alike,'like');
+ like_puller($a,$item,$dlike,'dislike');
+ }
+
+ $comments_collapsed = false;
+ $blowhard = 0;
+ $blowhard_count = 0;
+
+ foreach($items as $item) {
+
+ $comment = '';
+ $template = $tpl;
+ $commentww = '';
+ $sparkle = '';
+ $owner_url = $owner_photo = $owner_name = '';
+
+ // We've already parsed out like/dislike for special treatment. We can ignore them now
+
+ if(((activity_match($item['verb'],ACTIVITY_LIKE))
+ || (activity_match($item['verb'],ACTIVITY_DISLIKE)))
+ && ($item['id'] != $item['parent']))
+ continue;
+
+ $toplevelpost = (($item['id'] == $item['parent']) ? true : false);
+
+
+ // Take care of author collapsing and comment collapsing
+ // If a single author has more than 3 consecutive top-level posts, squash the remaining ones.
+ // If there are more than two comments, squash all but the last 2.
+
+ if($toplevelpost) {
+
+ $item_writeable = (($item['writable'] || $item['self']) ? true : false);
+
+ if($blowhard == $item['cid'] && (! $item['self']) && ($mode != 'profile') && ($mode != 'notes')) {
+ $blowhard_count ++;
+ if($blowhard_count == 3) {
+ $o .= '<div class="icollapse-wrapper fakelink" id="icollapse-wrapper-' . $item['parent']
+ . '" onclick="openClose(' . '\'icollapse-' . $item['parent'] . '\'); $(\'#icollapse-wrapper-' . $item['parent'] . '\').hide();" >'
+ . t('See more posts like this') . '</div>' . '<div class="icollapse" id="icollapse-'
+ . $item['parent'] . '" style="display: none;" >';
+ }
+ }
+ else {
+ $blowhard = $item['cid'];
+ if($blowhard_count >= 3)
+ $o .= '</div>';
+ $blowhard_count = 0;
+ }
+
+ $comments_seen = 0;
+ $comments_collapsed = false;
+ }
+ else
+ $comments_seen ++;
+
+
+ $override_comment_box = ((($page_writeable) && ($item_writeable)) ? true : false);
+ $show_comment_box = ((($page_writeable) && ($item_writeable) && ($comments_seen == $comments[$item['parent']])) ? true : false);
+
+ if(($comments[$item['parent']] > 2) && ($comments_seen <= ($comments[$item['parent']] - 2)) && ($item['gravity'] == 6)) {
+ if(! $comments_collapsed) {
+ $o .= '<div class="ccollapse-wrapper fakelink" id="ccollapse-wrapper-' . $item['parent']
+ . '" onclick="openClose(' . '\'ccollapse-' . $item['parent'] . '\'); $(\'#ccollapse-wrapper-' . $item['parent'] . '\').hide();" >'
+ . sprintf( t('See all %d comments'), $comments[$item['parent']]) . '</div>'
+ . '<div class="ccollapse" id="ccollapse-' . $item['parent'] . '" style="display: none;" >';
+ $comments_collapsed = true;
+ }
+ }
+ if(($comments[$item['parent']] > 2) && ($comments_seen == ($comments[$item['parent']] - 1))) {
+ $o .= '</div>';
+ }
+
+ $redirect_url = $a->get_baseurl() . '/redir/' . $item['cid'] ;
+
+ $lock = ((($item['private']) || (($item['uid'] == local_user()) && (strlen($item['allow_cid']) || strlen($item['allow_gid'])
+ || strlen($item['deny_cid']) || strlen($item['deny_gid']))))
+ ? '<div class="wall-item-lock"><img src="images/lock_icon.gif" class="lockview" alt="' . t('Private Message') . '" onclick="lockview(event,' . $item['id'] . ');" /></div>'
+ : '<div class="wall-item-lock"></div>');
+
+
+ // Top-level wall post not written by the wall owner (wall-to-wall)
+ // First figure out who owns it.
+
+ $osparkle = '';
+
+ if(($toplevelpost) && (! $item['self']) && ($mode !== 'profile')) {
+
+ if($item['type'] === 'wall') {
+
+ // On the network page, I am the owner. On the display page it will be the profile owner.
+ // This will have been stored in $a->page_contact by our calling page.
+ // Put this person on the left of the wall-to-wall notice.
+
+ $owner_url = $a->page_contact['url'];
+ $owner_photo = $a->page_contact['thumb'];
+ $owner_name = $a->page_contact['name'];
+ $template = $wallwall;
+ $commentww = 'ww';
+ }
+ if(($item['type'] === 'remote') && (strlen($item['owner-link'])) && ($item['owner-link'] != $item['author-link'])) {
+
+ // Could be anybody.
+
+ $owner_url = $item['owner-link'];
+ $owner_photo = $item['owner-avatar'];
+ $owner_name = $item['owner-name'];
+ $template = $wallwall;
+ $commentww = 'ww';
+ // If it is our contact, use a friendly redirect link
+ if((link_compare($item['owner-link'],$item['url']))
+ && ($item['network'] === 'dfrn')) {
+ $owner_url = $redirect_url;
+ $osparkle = ' sparkle';
+ }
+ }
+ }
+
+
+ $likebuttons = '';
+
+ if($page_writeable) {
+ if($toplevelpost) {
+ $likebuttons = replace_macros((($item['private']) ? $noshare_tpl : $like_tpl),array(
+ '$id' => $item['id'],
+ '$likethis' => t("I like this \x28toggle\x29"),
+ '$nolike' => t("I don't like this \x28toggle\x29"),
+ '$share' => t('Share'),
+ '$wait' => t('Please wait')
+ ));
+ }
+
+ if(($show_comment_box) || (($show_comment_box == false) && ($override_comment_box == false) && ($item['last-child']))) {
+ $comment = replace_macros($cmnt_tpl,array(
+ '$return_path' => '',
+ '$jsreload' => (($mode === 'display') ? $_SESSION['return_url'] : ''),
+ '$type' => (($mode === 'profile') ? 'wall-comment' : 'net-comment'),
+ '$id' => $item['item_id'],
+ '$parent' => $item['parent'],
+ '$profile_uid' => $profile_owner,
+ '$mylink' => $a->contact['url'],
+ '$mytitle' => t('This is you'),
+ '$myphoto' => $a->contact['thumb'],
+ '$comment' => t('Comment'),
+ '$submit' => t('Submit'),
+ '$ww' => (($mode === 'network') ? $commentww : '')
+ ));
+ }
+ }
+
+ $edpost = (((($profile_owner == local_user()) && ($toplevelpost) && (intval($item['wall']) == 1)) || ($mode === 'notes'))
+ ? '<a class="editpost" href="' . $a->get_baseurl() . '/editpost/' . $item['id']
+ . '" title="' . t('Edit') . '"><img src="images/pencil.gif" /></a>'
+ : '');
+ $drop = replace_macros(get_markup_template('wall_item_drop.tpl'), array('$id' => $item['id'], '$delete' => t('Delete')));
+
+ $photo = $item['photo'];
+ $thumb = $item['thumb'];
+
+ // Post was remotely authored.
+
+ $diff_author = ((link_compare($item['url'],$item['author-link'])) ? false : true);
+
+ $profile_name = (((strlen($item['author-name'])) && $diff_author) ? $item['author-name'] : $item['name']);
+
+ $sp = false;
+ $profile_link = best_link_url($item,$sp);
+ if($sp)
+ $sparkle = ' sparkle';
+
+ if($profile_link === 'mailbox')
+ $profile_link = '';
+
+ $normalised = normalise_link((strlen($item['author-link'])) ? $item['author-link'] : $item['url']);
+ if(($normalised != 'mailbox') && (x($a->contacts[$normalised])))
+ $profile_avatar = $a->contacts[$normalised]['thumb'];
+ else
+ $profile_avatar = (((strlen($item['author-avatar'])) && $diff_author) ? $item['author-avatar'] : $thumb);
+
+
+
+
+
+ $like = ((x($alike,$item['id'])) ? format_like($alike[$item['id']],$alike[$item['id'] . '-l'],'like',$item['id']) : '');
+ $dislike = ((x($dlike,$item['id'])) ? format_like($dlike[$item['id']],$dlike[$item['id'] . '-l'],'dislike',$item['id']) : '');
+
+ $location = (($item['location']) ? '<a target="map" title="' . $item['location']
+ . '" href="http://maps.google.com/?q=' . urlencode($item['location']) . '">' . $item['location'] . '</a>' : '');
+ $coord = (($item['coord']) ? '<a target="map" title="' . $item['coord']
+ . '" href="http://maps.google.com/?q=' . urlencode($item['coord']) . '">' . $item['coord'] . '</a>' : '');
+ if($coord) {
+ if($location)
+ $location .= '<br /><span class="smalltext">(' . $coord . ')</span>';
+ else
+ $location = '<span class="smalltext">' . $coord . '</span>';
+ }
+
+ $indent = (($toplevelpost) ? '' : ' comment');
+
+ if(strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC','now - 12 hours')) > 0)
+ $indent .= ' shiny';
+
+ //
+ localize_item($item);
+
+ // Build the HTML
+
+ $tmp_item = replace_macros($template,array(
+ '$id' => $item['item_id'],
+ '$linktitle' => sprintf( t('View %s\'s profile'), $profile_name),
+ '$olinktitle' => sprintf( t('View %s\'s profile'), $owner_name),
+ '$to' => t('to'),
+ '$wall' => t('Wall-to-Wall'),
+ '$vwall' => t('via Wall-To-Wall:'),
+ '$profile_url' => $profile_link,
+ '$item_photo_menu' => item_photo_menu($item),
+ '$name' => $profile_name,
+ '$thumb' => $profile_avatar,
+ '$osparkle' => $osparkle,
+ '$sparkle' => $sparkle,
+ '$title' => $item['title'],
+ '$body' => smilies(bbcode($item['body'])),
+ '$ago' => relative_date($item['created']),
+ '$lock' => $lock,
+ '$location' => $location,
+ '$indent' => $indent,
+ '$owner_url' => $owner_url,
+ '$owner_photo' => $owner_photo,
+ '$owner_name' => $owner_name,
+ '$plink' => get_plink($item),
+ '$edpost' => $edpost,
+ '$drop' => $drop,
+ '$vote' => $likebuttons,
+ '$like' => $like,
+ '$dislike' => $dislike,
+ '$comment' => $comment
+ ));
+
+ $arr = array('item' => $item, 'output' => $tmp_item);
+ call_hooks('display_item', $arr);
+
+ $o .= $arr['output'];
+
+ }
+ }
+
+
+ // if author collapsing is in force but didn't get closed, close it off now.
+
+ if($blowhard_count >= 3)
+ $o .= '</div>';
+
+ return $o;
+}
+
+
+if(! function_exists('load_contact_links')) {
+function load_contact_links($uid) {
+
+ $a = get_app();
+
+ $ret = array();
+
+ if(! $uid || x($a->contacts,'empty'))
+ return;
+
+ $r = q("SELECT `id`,`network`,`url`,`thumb` FROM `contact` WHERE `uid` = %d AND `self` = 0 AND `blocked` = 0 ",
+ intval($uid)
+ );
+ if(count($r)) {
+ foreach($r as $rr){
+ $url = normalise_link($rr['url']);
+ $ret[$url] = $rr;
+ }
+ }
+ else
+ $ret['empty'] = true;
+ $a->contacts = $ret;
+ return;
+}}
+
+
+function best_link_url($item,&$sparkle) {
+
+ $a = get_app();
+
+ $best_url = '';
+ $sparkle = false;
+
+ $clean_url = normalise_link($item['author-link']);
+
+ if((local_user()) && (local_user() == $item['uid'])) {
+ if(isset($a->contacts) && x($a->contacts,$clean_url)) {
+ if($a->contacts[$clean_url]['network'] === NETWORK_DFRN) {
+ $best_url = $a->get_baseurl() . '/redir/' . $a->contacts[$clean_url]['id'];
+ $sparkle = true;
+ }
+ else
+ $best_url = $a->contacts[$clean_url]['url'];
+ }
+ }
+ if(! $best_url) {
+ if(strlen($item['author-link']))
+ $best_url = $item['author-link'];
+ else
+ $best_url = $item['url'];
+ }
+
+ return $best_url;
+}
+
+
+if(! function_exists('item_photo_menu')){
+function item_photo_menu($item){
+ $a = get_app();
+
+ if (local_user() && (! count($a->contacts)))
+ load_contact_links(local_user());
+
+ $contact_url="";
+ $pm_url="";
+ $status_link="";
+ $photos_link="";
+ $posts_link="";
+
+ $sparkle = false;
+ $profile_link = best_link_url($item,$sparkle);
+ if($profile_link === 'mailbox')
+ $profile_link = '';
+
+ if($sparkle) {
+ $cid = intval(basename($profile_link));
+ $status_link = $profile_link . "?url=status";
+ $photos_link = $profile_link . "?url=photos";
+ $profile_link = $profile_link . "?url=profile";
+ $pm_url = $a->get_baseurl() . '/message/new/' . $cid;
+ }
+ else {
+ if(local_user() && local_user() == $item['uid'] && link_compare($item['url'],$item['author-link'])) {
+ $cid = $item['contact-id'];
+ }
+ else {
+ $cid = 0;
+ }
+ }
+ if(($cid) && (! $item['self'])) {
+ $contact_url = $a->get_baseurl() . '/contacts/' . $cid;
+ $posts_link = $a->get_baseurl() . '/network/?cid=' . $cid;
+ }
+
+ $menu = Array(
+ t("View status") => $status_link,
+ t("View profile") => $profile_link,
+ t("View photos") => $photos_link,
+ t("View recent") => $posts_link,
+ t("Edit contact") => $contact_url,
+ t("Send PM") => $pm_url,
+ );
+
+
+ $args = array($item, &$menu);
+
+ call_hooks('item_photo_menu', $args);
+
+ $o = "";
+ foreach($menu as $k=>$v){
+ if ($v!="") $o .= "<li><a href='$v'>$k</a></li>\n";
+ }
+ return $o;
+}}
+
+if(! function_exists('like_puller')) {
+function like_puller($a,$item,&$arr,$mode) {
+
+ $url = '';
+ $sparkle = '';
+ $verb = (($mode === 'like') ? ACTIVITY_LIKE : ACTIVITY_DISLIKE);
+
+ if((activity_match($item['verb'],$verb)) && ($item['id'] != $item['parent'])) {
+ $url = $item['author-link'];
+ if((local_user()) && (local_user() == $item['uid']) && ($item['network'] === 'dfrn') && (! $item['self']) && (link_compare($item['author-link'],$item['url']))) {
+ $url = $a->get_baseurl() . '/redir/' . $item['contact-id'];
+ $sparkle = ' class="sparkle" ';
+ }
+ if(! ((isset($arr[$item['parent'] . '-l'])) && (is_array($arr[$item['parent'] . '-l']))))
+ $arr[$item['parent'] . '-l'] = array();
+ if(! isset($arr[$item['parent']]))
+ $arr[$item['parent']] = 1;
+ else
+ $arr[$item['parent']] ++;
+ $arr[$item['parent'] . '-l'][] = '<a href="'. $url . '"'. $sparkle .'>' . $item['author-name'] . '</a>';
+ }
+ return;
+}}
+
+// Format the like/dislike text for a profile item
+// $cnt = number of people who like/dislike the item
+// $arr = array of pre-linked names of likers/dislikers
+// $type = one of 'like, 'dislike'
+// $id = item id
+// returns formatted text
+
+if(! function_exists('format_like')) {
+function format_like($cnt,$arr,$type,$id) {
+ $o = '';
+ if($cnt == 1)
+ $o .= (($type === 'like') ? sprintf( t('%s likes this.'), $arr[0]) : sprintf( t('%s doesn\'t like this.'), $arr[0])) . EOL ;
+ else {
+ $spanatts = 'class="fakelink" onclick="openClose(\'' . $type . 'list-' . $id . '\');"';
+ $o .= (($type === 'like') ?
+ sprintf( t('<span %1$s>%2$d people</span> like this.'), $spanatts, $cnt)
+ :
+ sprintf( t('<span %1$s>%2$d people</span> don\'t like this.'), $spanatts, $cnt) );
+ $o .= EOL ;
+ $total = count($arr);
+ if($total >= MAX_LIKERS)
+ $arr = array_slice($arr, 0, MAX_LIKERS - 1);
+ if($total < MAX_LIKERS)
+ $arr[count($arr)-1] = t('and') . ' ' . $arr[count($arr)-1];
+ $str = implode(', ', $arr);
+ if($total >= MAX_LIKERS)
+ $str .= sprintf( t(', and %d other people'), $total - MAX_LIKERS );
+ $str = (($type === 'like') ? sprintf( t('%s like this.'), $str) : sprintf( t('%s don\'t like this.'), $str));
+ $o .= "\t" . '<div id="' . $type . 'list-' . $id . '" style="display: none;" >' . $str . '</div>';
+ }
+ return $o;
+}}
+
+
+function status_editor($a,$x, $notes_cid = 0) {
+
+ $o = '';
+
+ $geotag = (($x['allow_location']) ? get_markup_template('jot_geotag.tpl') : '');
+
+ $tpl = get_markup_template('jot-header.tpl');
+
+ $a->page['htmlhead'] .= replace_macros($tpl, array(
+ '$baseurl' => $a->get_baseurl(),
+ '$geotag' => $geotag,
+ '$nickname' => $x['nickname'],
+ '$ispublic' => t('Visible to <strong>everybody</strong>'),
+ '$linkurl' => t('Please enter a link URL:'),
+ '$utubeurl' => t('Please enter a YouTube link:'),
+ '$vidurl' => t("Please enter a video\x28.ogg\x29 link/URL:"),
+ '$audurl' => t("Please enter an audio\x28.ogg\x29 link/URL:"),
+ '$whereareu' => t('Where are you right now?'),
+ '$title' => t('Enter a title for this item')
+ ));
+
+
+ $tpl = get_markup_template("jot.tpl");
+
+ $jotplugins = '';
+ $jotnets = '';
+
+ $mail_disabled = ((function_exists('imap_open') && (! get_config('system','imap_disabled'))) ? 0 : 1);
+
+ $mail_enabled = false;
+ $pubmail_enabled = false;
+
+ if(($x['is_owner']) && (! $mail_disabled)) {
+ $r = q("SELECT * FROM `mailacct` WHERE `uid` = %d AND `server` != '' LIMIT 1",
+ intval(local_user())
+ );
+ if(count($r)) {
+ $mail_enabled = true;
+ if(intval($r[0]['pubmail']))
+ $pubmail_enabled = true;
+ }
+ }
+
+ if($mail_enabled) {
+ $selected = (($pubmail_enabled) ? ' checked="checked" ' : '');
+ $jotnets .= '<div class="profile-jot-net"><input type="checkbox" name="pubmail_enable"' . $selected . 'value="1" /> '
+ . t("Post to Email") . '</div>';
+ }
+
+ call_hooks('jot_tool', $jotplugins);
+ call_hooks('jot_networks', $jotnets);
+
+ if($notes_cid)
+ $jotnets .= '<input type="hidden" name="contact_allow[]" value="' . $notes_cid .'" />';
+
+ $tpl = replace_macros($tpl,array('$jotplugins' => $jotplugins));
+
+ $o .= replace_macros($tpl,array(
+ '$return_path' => $a->cmd,
+ '$action' => 'item',
+ '$share' => (($x['button']) ? $x['button'] : t('Share')),
+ '$upload' => t('Upload photo'),
+ '$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'),
+ '$title' => t('Set title'),
+ '$wait' => t('Please wait'),
+ '$permset' => t('Permission settings'),
+ '$ptyp' => (($notes_cid) ? 'note' : 'wall'),
+ '$content' => '',
+ '$post_id' => '',
+ '$baseurl' => $a->get_baseurl(),
+ '$defloc' => $x['default_location'],
+ '$visitor' => $x['visitor'],
+ '$pvisit' => (($notes_cid) ? 'none' : $x['visitor']),
+ '$emailcc' => t('CC: email addresses'),
+ '$public' => t('Public post'),
+ '$jotnets' => $jotnets,
+ '$emtitle' => t('Example: bob@example.com, mary@example.com'),
+ '$lockstate' => $x['lockstate'],
+ '$acl' => $x['acl'],
+ '$bang' => $x['bang'],
+ '$profile_uid' => $x['profile_uid'],
+ ));
+
+ return $o;
+} \ No newline at end of file
diff --git a/include/dba.php b/include/dba.php
index d75ed560a..49b325cf7 100644
--- a/include/dba.php
+++ b/include/dba.php
@@ -19,6 +19,23 @@ class dba {
public $connected = false;
function __construct($server,$user,$pass,$db,$install = false) {
+
+ $server = trim($server);
+ $user = trim($user);
+ $pass = trim($pass);
+ $db = trim($db);
+
+ if($install) {
+ if(strlen($server) && ($server !== 'localhost') && ($server !== '127.0.0.1')) {
+ if(! dns_get_record($server, DNS_A + DNS_CNAME + DNS_PTR)) {
+ notice( sprintf( t('Cannot locate DNS info for database server \'%s\''), $server));
+ $this->connected = false;
+ $this->db = null;
+ return;
+ }
+ }
+ }
+
$this->db = @new mysqli($server,$user,$pass,$db);
if(! mysqli_connect_errno()) {
$this->connected = true;
@@ -61,7 +78,7 @@ class dba {
}
else {
- /*
+ /**
* If dbfail.out exists, we will write any failed calls directly to it,
* regardless of any logging that may or may nor be in effect.
* These usually indicate SQL syntax errors that need to be resolved.
diff --git a/include/email.php b/include/email.php
new file mode 100644
index 000000000..7e0351e94
--- /dev/null
+++ b/include/email.php
@@ -0,0 +1,201 @@
+<?php
+
+function email_connect($mailbox,$username,$password) {
+ if(! function_exists('imap_open'))
+ return false;
+
+ $mbox = imap_open($mailbox,$username,$password);
+
+ return $mbox;
+}
+
+function email_poll($mbox,$email_addr) {
+
+ if(! ($mbox && $email_addr))
+ return array();;
+
+ $search = imap_search($mbox,'FROM "' . $email_addr . '"', SE_UID);
+
+ $search2 = imap_search($mbox,'TO "' . $email_addr . '"', SE_UID);
+
+ if($search && $search2)
+ $res = array_merge($search,$search2);
+ elseif($search)
+ $res = $search;
+ else
+ $res = $search2;
+
+ return (($res) ? $res : array());
+}
+
+
+function construct_mailbox_name($mailacct) {
+ $ret = '{' . $mailacct['server'] . ((intval($mailacct['port'])) ? ':' . $mailacct['port'] : '');
+ $ret .= (($mailacct['ssltype']) ? '/' . $mailacct['ssltype'] . '/novalidate-cert' : '');
+ $ret .= '}' . $mailacct['mailbox'];
+ return $ret;
+}
+
+
+function email_msg_meta($mbox,$uid) {
+ $ret = (($mbox && $uid) ? imap_fetch_overview($mbox,$uid,FT_UID) : array(array()));
+ return ((count($ret)) ? $ret[0] : array());
+}
+
+function email_msg_headers($mbox,$uid) {
+ $raw_header = (($mbox && $uid) ? imap_fetchheader($mbox,$uid,FT_UID) : '');
+ $raw_header = str_replace("\r",'',$raw_header);
+ $ret = array();
+ $h = split("\n",$raw_header);
+ if(count($h))
+ foreach($h as $line ) {
+ if (preg_match("/^[a-zA-Z]/", $line)) {
+ $key = substr($line,0,strpos($line,':'));
+ $value = substr($line,strpos($line,':')+1);
+
+ $last_entry = strtolower($key);
+ $ret[$last_entry] = trim($value);
+ }
+ else {
+ $ret[$last_entry] .= ' ' . trim($line);
+ }
+ }
+ return $ret;
+}
+
+
+function email_get_msg($mbox,$uid) {
+ $ret = array();
+
+ $struc = (($mbox && $uid) ? imap_fetchstructure($mbox,$uid,FT_UID) : null);
+
+ if(! $struc)
+ return $ret;
+
+ if(! $struc->parts) {
+ $ret['body'] = email_get_part($mbox,$uid,$struc,0);
+ }
+ else {
+ foreach($struc->parts as $ptop => $p) {
+ $x = email_get_part($mbox,$uid,$p,$ptop + 1);
+ if($x)
+ $ret['body'] = $x;
+ }
+ }
+ return $ret;
+}
+
+// At the moment - only return plain/text.
+// Later we'll repackage inline images as data url's and make the HTML safe
+
+function email_get_part($mbox,$uid,$p,$partno) {
+ // $partno = '1', '2', '2.1', '2.1.3', etc for multipart, 0 if simple
+ global $htmlmsg,$plainmsg,$charset,$attachments;
+
+ echo $partno;
+
+ // DECODE DATA
+ $data = ($partno)
+ ? imap_fetchbody($mbox,$uid,$partno, FT_UID|FT_PEEK)
+ : imap_body($mbox,$uid,FT_UID|FT_PEEK);
+
+ // Any part may be encoded, even plain text messages, so check everything.
+ if ($p->encoding==4)
+ $data = quoted_printable_decode($data);
+ elseif ($p->encoding==3)
+ $data = base64_decode($data);
+
+ // PARAMETERS
+ // get all parameters, like charset, filenames of attachments, etc.
+ $params = array();
+ if ($p->parameters)
+ foreach ($p->parameters as $x)
+ $params[strtolower($x->attribute)] = $x->value;
+ if ($p->dparameters)
+ foreach ($p->dparameters as $x)
+ $params[strtolower($x->attribute)] = $x->value;
+
+ // ATTACHMENT
+ // Any part with a filename is an attachment,
+ // so an attached text file (type 0) is not mistaken as the message.
+
+ if ($params['filename'] || $params['name']) {
+ // filename may be given as 'Filename' or 'Name' or both
+ $filename = ($params['filename'])? $params['filename'] : $params['name'];
+ // filename may be encoded, so see imap_mime_header_decode()
+ $attachments[$filename] = $data; // this is a problem if two files have same name
+ }
+
+ // TEXT
+ if ($p->type == 0 && $data) {
+ // Messages may be split in different parts because of inline attachments,
+ // so append parts together with blank row.
+ if (strtolower($p->subtype)=='plain')
+ return (trim($data) ."\n\n");
+ else
+ $data = '';
+
+ // $htmlmsg .= $data ."<br><br>";
+ $charset = $params['charset']; // assume all parts are same charset
+ }
+
+ // EMBEDDED MESSAGE
+ // Many bounce notifications embed the original message as type 2,
+ // but AOL uses type 1 (multipart), which is not handled here.
+ // There are no PHP functions to parse embedded messages,
+ // so this just appends the raw source to the main message.
+// elseif ($p->type==2 && $data) {
+// $plainmsg .= $data."\n\n";
+// }
+
+ // SUBPART RECURSION
+ if ($p->parts) {
+ foreach ($p->parts as $partno0=>$p2) {
+ $x = email_get_part($mbox,$uid,$p2,$partno . '.' . ($partno0+1)); // 1.2, 1.2.1, etc.
+ if($x)
+ return $x;
+ }
+ }
+}
+
+
+
+function email_header_encode($in_str, $charset) {
+ $out_str = $in_str;
+ if ($out_str && $charset) {
+
+ // define start delimimter, end delimiter and spacer
+ $end = "?=";
+ $start = "=?" . $charset . "?B?";
+ $spacer = $end . "\r\n " . $start;
+
+ // determine length of encoded text within chunks
+ // and ensure length is even
+ $length = 75 - strlen($start) - strlen($end);
+
+ /*
+ [EDIT BY danbrown AT php DOT net: The following
+ is a bugfix provided by (gardan AT gmx DOT de)
+ on 31-MAR-2005 with the following note:
+ "This means: $length should not be even,
+ but divisible by 4. The reason is that in
+ base64-encoding 3 8-bit-chars are represented
+ by 4 6-bit-chars. These 4 chars must not be
+ split between two encoded words, according
+ to RFC-2047.
+ */
+ $length = $length - ($length % 4);
+
+ // encode the string and split it into chunks
+ // with spacers after each chunk
+ $out_str = base64_encode($out_str);
+ $out_str = chunk_split($out_str, $length, $spacer);
+
+ // remove trailing spacer and
+ // add start and end delimiters
+ $spacer = preg_quote($spacer);
+ $out_str = preg_replace("/" . $spacer . "$/", "", $out_str);
+ $out_str = $start . $out_str . $end;
+ }
+ return $out_str;
+} \ No newline at end of file
diff --git a/include/expire.php b/include/expire.php
new file mode 100644
index 000000000..3c30e01c1
--- /dev/null
+++ b/include/expire.php
@@ -0,0 +1,44 @@
+<?php
+
+require_once("boot.php");
+
+function expire_run($argv, $argc){
+ global $a, $db;
+
+ if(is_null($a)) {
+ $a = new App;
+ }
+
+ if(is_null($db)) {
+ @include(".htconfig.php");
+ require_once("dba.php");
+ $db = new dba($db_host, $db_user, $db_pass, $db_data);
+ unset($db_host, $db_user, $db_pass, $db_data);
+ };
+
+ require_once('session.php');
+ require_once('datetime.php');
+ require_once('simplepie/simplepie.inc');
+ require_once('include/items.php');
+ require_once('include/Contact.php');
+
+ $a->set_baseurl(get_config('system','url'));
+
+
+ logger('expire: start');
+
+ $r = q("SELECT `uid`,`username`,`expire` FROM `user` WHERE `expire` != 0");
+ if(count($r)) {
+ foreach($r as $rr) {
+ logger('Expire: ' . $rr['username'] . ' interval: ' . $rr['expire'], LOGGER_DEBUG);
+ item_expire($rr['uid'],$rr['expire']);
+ }
+ }
+
+ return;
+}
+
+if (array_search(__file__,get_included_files())===0){
+ expire_run($argv,$argc);
+ killme();
+}
diff --git a/include/fcontact.php b/include/fcontact.php
new file mode 100644
index 000000000..8821a985f
--- /dev/null
+++ b/include/fcontact.php
@@ -0,0 +1,41 @@
+<?php
+
+
+
+function fcontact_store($url,$name,$photo) {
+
+ $nurl = str_replace(array('https:','//www.'), array('http:','//'), $url);
+
+ $r = q("SELECT `id` FROM `fcontact` WHERE `url` = '%s' LIMIT 1",
+ dbesc($nurl)
+ );
+
+ if(count($r))
+ return $r[0]['id'];
+
+ $r = q("INSERT INTO `fcontact` ( `url`, `name`, `photo` ) VALUES ( '%s', '%s', '%s' ) ",
+ dbesc($nurl),
+ dbesc($name),
+ dbesc($photo)
+ );
+
+ if($r) {
+ $r = q("SELECT `id` FROM `fcontact` WHERE `url` = '%s' LIMIT 1",
+ dbesc($nurl)
+ );
+ if(count($r))
+ return $r[0]['id'];
+ }
+
+ return 0;
+}
+
+function ffinder_store($uid,$cid,$fid) {
+ $r = q("INSERT INTO `ffinder` ( `uid`, `cid`, `fid` ) VALUES ( %d, %d, %d ) ",
+ intval($uid),
+ intval($cid),
+ intval($fid)
+ );
+ return $r;
+}
+
diff --git a/include/group.php b/include/group.php
index 793e854be..8866104fc 100644
--- a/include/group.php
+++ b/include/group.php
@@ -108,9 +108,9 @@ function group_get_members($gid) {
if(intval($gid)) {
$r = q("SELECT `group_member`.`contact-id`, `contact`.* FROM `group_member`
LEFT JOIN `contact` ON `contact`.`id` = `group_member`.`contact-id`
- WHERE `gid` = %d AND `group_member`.`uid` = %d",
+ WHERE `gid` = %d AND `group_member`.`uid` = %d ORDER BY `contact`.`name` ASC ",
intval($gid),
- intval($_SESSION['uid'])
+ intval(local_user())
);
if(count($r))
$ret = $r;
@@ -118,9 +118,25 @@ function group_get_members($gid) {
return $ret;
}
+function group_public_members($gid) {
+ $ret = 0;
+ if(intval($gid)) {
+ $r = q("SELECT `contact`.`id` AS `contact-id` FROM `group_member`
+ LEFT JOIN `contact` ON `contact`.`id` = `group_member`.`contact-id`
+ WHERE `gid` = %d AND `group_member`.`uid` = %d
+ AND `contact`.`network` != 'dfrn' AND `contact`.`network` != 'mail' AND `contact`.`network` != 'face' ",
+ intval($gid),
+ intval(local_user())
+ );
+ if(count($r))
+ $ret = count($r);
+ }
+ return $ret;
+}
+
-function group_side($every="contacts",$each="group") {
+function group_side($every="contacts",$each="group",$edit = false) {
$o = '';
@@ -150,7 +166,7 @@ EOT;
);
if(count($r)) {
foreach($r as $rr)
- $o .= " <li class=\"sidebar-group-li\"><a href=\"$each/{$rr['id']}\">{$rr['name']}</a></li>\r\n";
+ $o .= ' <li class="sidebar-group-li">' . (($edit) ? "<a href=\"group/{$rr['id']}\" title=\"" . t('Edit') . "\" ><img src=\"images/spencil.gif\" alt=\"" . t('Edit') . "\"></a> " : "") . "<a href=\"$each/{$rr['id']}\">{$rr['name']}</a></li>\r\n";
}
$o .= " </ul>\r\n </div>\r\n</div>";
diff --git a/include/hostxrd.php b/include/hostxrd.php
index 9161b265c..987175c33 100644
--- a/include/hostxrd.php
+++ b/include/hostxrd.php
@@ -1,10 +1,10 @@
<?php
-function hostxrd($hostname) {
+function hostxrd($baseurl) {
header("Content-type: text/xml");
$tpl = file_get_contents('view/xrd_host.tpl');
- echo str_replace('$domain',$hostname,$tpl);
+ echo str_replace('$domain',$baseurl,$tpl);
session_write_close();
exit();
diff --git a/include/items.php b/include/items.php
index e930ab5d2..55b17158a 100644
--- a/include/items.php
+++ b/include/items.php
@@ -113,7 +113,7 @@ function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0)
$items = $r;
- $feed_template = load_view_file('view/atom_feed.tpl');
+ $feed_template = get_markup_template('atom_feed.tpl');
$atom = '';
@@ -180,7 +180,7 @@ function construct_activity_object($item) {
if($item['object']) {
$o = '<as:object>' . "\r\n";
- $r = @simplexml_load_string($item['object']);
+ $r = parse_xml_string($item['object']);
if($r->type)
$o .= '<as:object-type>' . xmlify($r->type) . '</as:object-type>' . "\r\n";
if($r->id)
@@ -206,7 +206,7 @@ function construct_activity_target($item) {
if($item['target']) {
$o = '<as:target>' . "\r\n";
- $r = @simplexml_load_string($item['target']);
+ $r = parse_xml_string($item['target']);
if($r->type)
$o .= '<as:object-type>' . xmlify($r->type) . '</as:object-type>' . "\r\n";
if($r->id)
@@ -241,8 +241,14 @@ function get_atom_elements($feed,$item) {
$res = array();
$author = $item->get_author();
- $res['author-name'] = unxmlify($author->get_name());
- $res['author-link'] = unxmlify($author->get_link());
+ if($author) {
+ $res['author-name'] = unxmlify($author->get_name());
+ $res['author-link'] = unxmlify($author->get_link());
+ }
+ else {
+ $res['author-name'] = unxmlify($feed->get_title());
+ $res['author-link'] = unxmlify($feed->get_permalink());
+ }
$res['uri'] = unxmlify($item->get_id());
$res['title'] = unxmlify($item->get_title());
$res['body'] = unxmlify($item->get_content());
@@ -343,12 +349,14 @@ function get_atom_elements($feed,$item) {
// the wild, by sanitising it and converting supported tags to bbcode before we rip out any remaining
// html.
-
if((strpos($res['body'],'<') !== false) || (strpos($res['body'],'>') !== false)) {
$res['body'] = preg_replace('#<object[^>]+>.+?' . 'http://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?</object>#s',
'[youtube]$1[/youtube]', $res['body']);
+ $res['body'] = preg_replace('#<iframe[^>].+?' . 'http://www.youtube.com/embed/([A-Za-z0-9\-_=]+).+?</iframe>#s',
+ '[youtube]$1[/youtube]', $res['body']);
+
$res['body'] = oembed_html2bbcode($res['body']);
$config = HTMLPurifier_Config::createDefault();
@@ -401,6 +409,17 @@ function get_atom_elements($feed,$item) {
$res['edited'] = $item->get_date('c');
+ // Disallow time travelling posts
+
+ $d1 = strtotime($res['created']);
+ $d2 = strtotime($res['edited']);
+ $d3 = strtotime('now');
+
+ if($d1 > $d3)
+ $res['created'] = datetime_convert();
+ if($d2 > $d3)
+ $res['edited'] = datetime_convert();
+
$rawowner = $item->get_item_tags(NAMESPACE_DFRN, 'owner');
if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])
$res['owner-name'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']);
@@ -440,7 +459,45 @@ function get_atom_elements($feed,$item) {
if((x($res,'verb')) && ($res['verb'] === 'http://ostatus.org/schema/1.0/unfollow'))
$res['verb'] = ACTIVITY_UNFOLLOW;
-
+
+ $cats = $item->get_categories();
+ if($cats) {
+ $tag_arr = array();
+ foreach($cats as $cat) {
+ $term = $cat->get_term();
+ if(! $term)
+ $term = $cat->get_label();
+ $scheme = $cat->get_scheme();
+ if($scheme && $term && stristr($scheme,'X-DFRN:'))
+ $tag_arr[] = substr($scheme,7,1) . '[url=' . unxmlify(substr($scheme,9)) . ']' . unxmlify($term) . '[/url]';
+ elseif($term)
+ $tag_arr[] = notags(trim($term));
+ }
+ $res['tag'] = implode(',', $tag_arr);
+ }
+
+ $attach = $item->get_enclosures();
+ if($attach) {
+ $att_arr = array();
+ foreach($attach as $att) {
+ $len = intval($att->get_length());
+ $link = str_replace(array(',','"'),array('%2D','%22'),notags(trim(unxmlify($att->get_link()))));
+ $title = str_replace(array(',','"'),array('%2D','%22'),notags(trim(unxmlify($att->get_title()))));
+ $type = str_replace(array(',','"'),array('%2D','%22'),notags(trim(unxmlify($att->get_type()))));
+ if(strpos($type,';'))
+ $type = substr($type,0,strpos($type,';'));
+ if((! $link) || (strpos($link,'http') !== 0))
+ continue;
+
+ if(! $title)
+ $title = ' ';
+ if(! $type)
+ $type = 'application/octet-stream';
+
+ $att_arr[] = '[attach]href="' . $link . '" size="' . $len . '" type="' . $type . '" title="' . $title . '"[/attach]';
+ }
+ $res['attach'] = implode(',', $att_arr);
+ }
$rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'object');
@@ -467,6 +524,10 @@ function get_atom_elements($feed,$item) {
$body = preg_replace('#<object[^>]+>.+?' . 'http://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?</object>#s',
'[youtube]$1[/youtube]', $body);
+ $res['body'] = preg_replace('#<iframe[^>].+?' . 'http://www.youtube.com/embed/([A-Za-z0-9\-_=]+).+?</iframe>#s',
+ '[youtube]$1[/youtube]', $res['body']);
+
+
$config = HTMLPurifier_Config::createDefault();
$config->set('Cache.DefinitionImpl', null);
@@ -506,6 +567,9 @@ function get_atom_elements($feed,$item) {
$body = preg_replace('#<object[^>]+>.+?' . 'http://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?</object>#s',
'[youtube]$1[/youtube]', $body);
+ $res['body'] = preg_replace('#<iframe[^>].+?' . 'http://www.youtube.com/embed/([A-Za-z0-9\-_=]+).+?</iframe>#s',
+ '[youtube]$1[/youtube]', $res['body']);
+
$config = HTMLPurifier_Config::createDefault();
$config->set('Cache.DefinitionImpl', null);
@@ -598,6 +662,8 @@ function item_store($arr,$force_parent = false) {
$arr['deny_gid'] = ((x($arr,'deny_gid')) ? trim($arr['deny_gid']) : '');
$arr['private'] = ((x($arr,'private')) ? intval($arr['private']) : 0 );
$arr['body'] = ((x($arr,'body')) ? trim($arr['body']) : '');
+ $arr['tag'] = ((x($arr,'tag')) ? notags(trim($arr['tag'])) : '');
+ $arr['attach'] = ((x($arr,'attach')) ? notags(trim($arr['attach'])) : '');
if($arr['parent-uri'] === $arr['uri']) {
$parent_id = 0;
@@ -645,6 +711,7 @@ function item_store($arr,$force_parent = false) {
$parent_id = 0;
$arr['thr-parent'] = $arr['parent-uri'];
$arr['parent-uri'] = $arr['uri'];
+ $arr['gravity'] = 0;
}
else {
logger('item_store: item parent was not found - ignoring item');
@@ -702,6 +769,18 @@ function item_store($arr,$force_parent = false) {
intval($current_post)
);
+ /**
+ * If this is now the last-child, force all _other_ children of this parent to *not* be last-child
+ */
+
+ if($arr['last-child']) {
+ $r = q("UPDATE `item` SET `last-child` = 0 WHERE `parent-uri` = '%s' AND `uid` = %d AND `id` != %d",
+ dbesc($arr['uri']),
+ intval($arr['uid']),
+ intval($current_post)
+ );
+ }
+
return $current_post;
}
@@ -739,7 +818,7 @@ function dfrn_deliver($owner,$contact,$atom, $dissolve = false) {
if(! $rino_enable)
$rino = 0;
- $url = $contact['notify'] . '?dfrn_id=' . $idtosend . '&dfrn_version=' . DFRN_PROTOCOL_VERSION . (($rino) ? '&rino=1' : '');
+ $url = $contact['notify'] . '&dfrn_id=' . $idtosend . '&dfrn_version=' . DFRN_PROTOCOL_VERSION . (($rino) ? '&rino=1' : '');
logger('dfrn_deliver: ' . $url);
@@ -760,7 +839,7 @@ function dfrn_deliver($owner,$contact,$atom, $dissolve = false) {
return 3;
}
- $res = simplexml_load_string($xml);
+ $res = parse_xml_string($xml);
if((intval($res->status) != 0) || (! strlen($res->challenge)) || (! strlen($res->dfrn_id)))
return (($res->status) ? $res->status : 3);
@@ -799,14 +878,14 @@ function dfrn_deliver($owner,$contact,$atom, $dissolve = false) {
if($dissolve)
$postvars['dissolve'] = '1';
- if(($contact['rel']) && ($contact['rel'] != REL_FAN) && (! $contact['blocked']) && (! $contact['readonly'])) {
- $postvars['data'] = $atom;
- }
- elseif($owner['page-flags'] == PAGE_COMMUNITY) {
+
+ if((($contact['rel']) && ($contact['rel'] != REL_FAN) && (! $contact['blocked'])) || ($owner['page-flags'] == PAGE_COMMUNITY)) {
$postvars['data'] = $atom;
+ $postvars['perm'] = 'rw';
}
else {
$postvars['data'] = str_replace('<dfrn:comment-allow>1','<dfrn:comment-allow>0',$atom);
+ $postvars['perm'] = 'r';
}
if($rino && $rino_allowed && (! $dissolve)) {
@@ -848,17 +927,15 @@ function dfrn_deliver($owner,$contact,$atom, $dissolve = false) {
if((! $curl_stat) || (! strlen($xml)))
return(-1); // timed out
-
if(strpos($xml,'<?xml') === false) {
logger('dfrn_deliver: phase 2: no valid XML returned');
logger('dfrn_deliver: phase 2: returned XML: ' . $xml, LOGGER_DATA);
return 3;
}
- $res = simplexml_load_string($xml);
+ $res = parse_xml_string($xml);
- return $res->status;
-
+ return $res->status;
}
@@ -878,7 +955,7 @@ function dfrn_deliver($owner,$contact,$atom, $dissolve = false) {
*
*/
-function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0) {
+function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $secure_feed = false) {
require_once('simplepie/simplepie.inc');
@@ -893,6 +970,7 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0) {
if($feed->error())
logger('consume_feed: Error parsing XML: ' . $feed->error());
+ $permalink = $feed->get_permalink();
// Check at the feed level for updated contact name and/or photo
@@ -1137,6 +1215,13 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0) {
$item_id = $item->get_id();
$datarray = get_atom_elements($feed,$item);
+ if(! x($datarray,'author-name'))
+ $datarray['author-name'] = $contact['name'];
+ if(! x($datarray,'author-link'))
+ $datarray['author-link'] = $contact['url'];
+ if(! x($datarray,'author-avatar'))
+ $datarray['author-avatar'] = $contact['thumb'];
+
$r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
dbesc($item_id),
intval($importer['uid'])
@@ -1207,8 +1292,18 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0) {
// Head post of a conversation. Have we seen it? If not, import it.
$item_id = $item->get_id();
+
$datarray = get_atom_elements($feed,$item);
+ if(is_array($contact)) {
+ if(! x($datarray,'author-name'))
+ $datarray['author-name'] = $contact['name'];
+ if(! x($datarray,'author-link'))
+ $datarray['author-link'] = $contact['url'];
+ if(! x($datarray,'author-avatar'))
+ $datarray['author-avatar'] = $contact['thumb'];
+ }
+
$r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
dbesc($item_id),
intval($importer['uid'])
@@ -1252,7 +1347,7 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0) {
if(! is_array($contact))
return;
- if($contact['network'] === 'stat') {
+ if($contact['network'] === 'stat' || stristr($permalink,'twitter.com')) {
if(strlen($datarray['title']))
unset($datarray['title']);
$datarray['last-child'] = 1;
@@ -1299,8 +1394,8 @@ function new_follower($importer,$contact,$datarray,$item) {
// create contact record - set to readonly
$r = q("INSERT INTO `contact` ( `uid`, `created`, `url`, `name`, `nick`, `photo`, `network`, `rel`,
- `blocked`, `readonly`, `pending` )
- VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, 0, 1, 1 ) ",
+ `blocked`, `readonly`, `pending`, `writable` )
+ VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, 0, 1, 1, 1 ) ",
intval($importer['uid']),
dbesc(datetime_convert()),
dbesc($url),
@@ -1336,7 +1431,7 @@ function new_follower($importer,$contact,$datarray,$item) {
$a = get_app();
if(count($r)) {
if(($r[0]['notify-flags'] & NOTIFY_INTRO) && ($r[0]['page-flags'] == PAGE_NORMAL)) {
- $email_tpl = load_view_file('view/follow_notify_eml.tpl');
+ $email_tpl = get_intltext_template('follow_notify_eml.tpl');
$email = replace_macros($email_tpl, array(
'$requestor' => ((strlen($name)) ? $name : t('[Name Withheld]')),
'$url' => $url,
@@ -1347,7 +1442,9 @@ function new_follower($importer,$contact,$datarray,$item) {
$res = mail($r[0]['email'],
t("You have a new follower at ") . $a->config['sitename'],
$email,
- 'From: ' . t('Administrator') . '@' . $_SERVER['SERVER_NAME'] );
+ 'From: ' . t('Administrator') . '@' . $_SERVER['SERVER_NAME'] . "\n"
+ . 'Content-type: text/plain; charset=UTF-8' . "\n"
+ . 'Content-transfer-encoding: 8bit' );
}
}
@@ -1426,17 +1523,24 @@ function atom_author($tag,$name,$uri,$h,$w,$photo) {
function atom_entry($item,$type,$author,$owner,$comment = false) {
+ $a = get_app();
+
if($item['deleted'])
return '<at:deleted-entry ref="' . xmlify($item['uri']) . '" when="' . xmlify(datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME)) . '" />' . "\r\n";
- $a = get_app();
+
+ if($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid'])
+ $body = fix_private_photos($item['body'],$owner['uid']);
+ else
+ $body = $item['body'];
+
$o = "\r\n\r\n<entry>\r\n";
if(is_array($author))
$o .= atom_author('author',$author['name'],$author['url'],80,80,$author['thumb']);
else
- $o .= atom_author('author',$item['name'],$item['url'],80,80,$item['thumb']);
+ $o .= atom_author('author',(($item['author-name']) ? $item['author-name'] : $item['name']),(($item['author-link']) ? $item['author-link'] : $item['url']),80,80,(($item['author-avatar']) ? $item['author-avatar'] : $item['thumb']));
if(strlen($item['owner-name']))
$o .= atom_author('dfrn:owner',$item['owner-name'],$item['owner-link'],80,80,$item['owner-avatar']);
@@ -1447,8 +1551,8 @@ function atom_entry($item,$type,$author,$owner,$comment = false) {
$o .= '<title>' . xmlify($item['title']) . '</title>' . "\r\n";
$o .= '<published>' . xmlify(datetime_convert('UTC','UTC',$item['created'] . '+00:00',ATOM_TIME)) . '</published>' . "\r\n";
$o .= '<updated>' . xmlify(datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME)) . '</updated>' . "\r\n";
- $o .= '<dfrn:env>' . base64url_encode($item['body'], true) . '</dfrn:env>' . "\r\n";
- $o .= '<content type="' . $type . '" >' . xmlify(($type === 'html') ? bbcode($item['body']) : $item['body']) . '</content>' . "\r\n";
+ $o .= '<dfrn:env>' . base64url_encode($body, true) . '</dfrn:env>' . "\r\n";
+ $o .= '<content type="' . $type . '" >' . xmlify(($type === 'html') ? bbcode($body) : $body) . '</content>' . "\r\n";
$o .= '<link rel="alternate" type="text/html" href="' . xmlify($a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id']) . '" />' . "\r\n";
if($comment)
$o .= '<dfrn:comment-allow>' . intval($item['last-child']) . '</dfrn:comment-allow>' . "\r\n";
@@ -1473,6 +1577,15 @@ function atom_entry($item,$type,$author,$owner,$comment = false) {
if(strlen($actarg))
$o .= $actarg;
+ $tags = item_getfeedtags($item);
+ if(count($tags)) {
+ foreach($tags as $t) {
+ $o .= '<category scheme="X-DFRN:' . xmlify($t[0]) . ':' . xmlify($t[1]) . '" term="' . xmlify($t[2]) . '" />' . "\r\n";
+ }
+ }
+
+ $o .= item_getfeedattach($item);
+
$mentioned = get_mentions($item);
if($mentioned)
$o .= $mentioned;
@@ -1483,4 +1596,125 @@ function atom_entry($item,$type,$author,$owner,$comment = false) {
return $o;
}
+
+function fix_private_photos($s,$uid) {
+ $a = get_app();
+ logger('fix_private_photos');
+
+ if(preg_match("/\[img\](.+?)\[\/img\]/is",$s,$matches)) {
+ $image = $matches[1];
+ logger('fix_private_photos: found photo ' . $image);
+ if(stristr($image ,$a->get_baseurl() . '/photo/')) {
+ $i = basename($image);
+ $i = str_replace('.jpg','',$i);
+ $x = strpos($i,'-');
+ if($x) {
+ $res = substr($i,$x+1);
+ $i = substr($i,0,$x);
+ $r = q("SELECT * FROM `photo` WHERE `resource-id` = '%s' AND `scale` = %d AND `uid` = %d",
+ dbesc($i),
+ intval($res),
+ intval($uid)
+ );
+ if(count($r)) {
+ logger('replacing photo');
+ $s = str_replace($image, 'data:image/jpg;base64,' . base64_encode($r[0]['data']), $s);
+ }
+ }
+ logger('fix_private_photos: replaced: ' . $s, LOGGER_DATA);
+ }
+ }
+ return($s);
+}
+
+
+
+function item_getfeedtags($item) {
+ $ret = array();
+ $matches = false;
+ $cnt = preg_match_all('|\#\[url\=(.+?)\](.+?)\[\/url\]|',$item['tag'],$matches);
+ if($cnt) {
+ for($x = 0; $x < count($matches); $x ++) {
+ if($matches[1][$x])
+ $ret[] = array('#',$matches[1][$x], $matches[2][$x]);
+ }
+ }
+ $matches = false;
+ $cnt = preg_match_all('|\@\[url\=(.+?)\](.+?)\[\/url\]|',$item['tag'],$matches);
+ if($cnt) {
+ for($x = 0; $x < count($matches); $x ++) {
+ if($matches[1][$x])
+ $ret[] = array('#',$matches[1][$x], $matches[2][$x]);
+ }
+ }
+ return $ret;
+}
+
+function item_getfeedattach($item) {
+ $ret = '';
+ $arr = explode(',',$item['attach']);
+ if(count($arr)) {
+ foreach($arr as $r) {
+ $matches = false;
+ $cnt = preg_match('|\[attach\]href=\"(.+?)\" size=\"(.+?)\" type=\"(.+?)\" title=\"(.+?)\"\[\/attach\]|',$r,$matches);
+ if($cnt) {
+ $ret .= '<link rel="enclosure" href="' . xmlify($matches[1]) . '" type="' . xmlify($matches[3]) . '" ';
+ if(intval($matches[2]))
+ $ret .= 'size="' . intval($matches[2]) . '" ';
+ if($matches[4] !== ' ')
+ $ret .= 'title="' . xmlify(trim($matches[4])) . '" ';
+ $ret .= ' />' . "\r\n";
+ }
+ }
+ }
+ return $ret;
+}
+
+
+function item_expire($uid,$days) {
+
+ if((! $uid) || (! $days))
+ return;
+
+ $r = q("SELECT * FROM `item`
+ WHERE `uid` = %d
+ AND `created` < UTC_TIMESTAMP() - INTERVAL %d DAY
+ AND `id` = `parent`
+ AND `deleted` = 0",
+ intval($uid),
+ intval($days)
+ );
+
+ if(! count($r))
+ return;
+
+ logger('expire: # items=' . count($r) );
+
+ foreach($r as $item) {
+
+ // Only expire posts, not photos and photo comments
+
+ if(strlen($item['resource-id']))
+ continue;
+
+ $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s' WHERE `id` = %d LIMIT 1",
+ dbesc(datetime_convert()),
+ dbesc(datetime_convert()),
+ intval($item['id'])
+ );
+
+ // kill the kids
+
+ $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d ",
+ dbesc(datetime_convert()),
+ dbesc(datetime_convert()),
+ dbesc($item['parent-uri']),
+ intval($item['uid'])
+ );
+
+ }
+
+ proc_run('php',"include/notifier.php","expire","$uid");
+
+} \ No newline at end of file
diff --git a/include/main.js b/include/main.js
index 824f2dfdf..0d68c2b2b 100644
--- a/include/main.js
+++ b/include/main.js
@@ -26,6 +26,8 @@
var pr = 0;
var liking = 0;
var in_progress = false;
+ var langSelect = false;
+ var commentBusy = false;
$(document).ready(function() {
$.ajaxSetup({cache: false});
@@ -45,6 +47,18 @@
$('#pause').html('');
}
}
+ // F8 - show/hide language selector
+ if(event.keyCode == '119') {
+ if(langSelect) {
+ langSelect = false;
+ $('#language-selector').hide();
+ }
+ else {
+ langSelect = true;
+ $('#language-selector').show();
+ }
+ }
+
// this is shift-home on FF, but $ on IE, disabling until I figure out why the diff.
// update: incompatible usage of onKeyDown vs onKeyPress
// if(event.keyCode == '36' && event.shiftKey == true) {
@@ -77,26 +91,26 @@
$.get("ping",function(data) {
$(data).find('result').each(function() {
var net = $(this).find('net').text();
- if(net == 0) { net = ''; }
+ if(net == 0) { net = ''; $('#net-update').hide() } else { $('#net-update').show() }
$('#net-update').html(net);
var home = $(this).find('home').text();
- if(home == 0) { home = ''; }
+ if(home == 0) { home = ''; $('#home-update').hide() } else { $('#home-update').show() }
$('#home-update').html(home);
var mail = $(this).find('mail').text();
- if(mail == 0) { mail = ''; }
+ if(mail == 0) { mail = ''; $('#mail-update').hide() } else { $('#mail-update').show() }
$('#mail-update').html(mail);
var intro = $(this).find('intro').text();
var register = $(this).find('register').text();
if(intro == 0) { intro = ''; }
if(register != 0 && intro != '') { intro = intro+'/'+register; }
if(register != 0 && intro == '') { intro = '0/'+register; }
+ if (intro == '') { $('#notify-update').hide() } else { $('#notify-update').show() }
$('#notify-update').html(intro);
});
}) ;
}
timer = setTimeout(NavUpdate,30000);
-
}
function liveUpdate() {
@@ -113,12 +127,21 @@
$.get(update_url,function(data) {
in_progress = false;
+ $('.ccollapse-wrapper',data).each(function() {
+ var ident = $(this).attr('id');
+ var is_hidden = $('#' + ident).is(':hidden');
+ if($('#' + ident).length) {
+ $('#' + ident).replaceWith($(this));
+ if(is_hidden)
+ $('#' + ident).hide();
+ }
+ });
$('.wall-item-outside-wrapper',data).each(function() {
var ident = $(this).attr('id');
- if($('#' + ident).length == 0) {
- $('img',this).each(function() {
- $(this).attr('src',$(this).attr('dst'));
- });
+ if($('#' + ident).length == 0) {
+ $('img',this).each(function() {
+ $(this).attr('src',$(this).attr('dst'));
+ });
$('#' + prev).after($(this));
}
else {
@@ -127,29 +150,26 @@
$('#' + ident + ' ' + '.wall-item-comment-wrapper').replaceWith($(this).find('.wall-item-comment-wrapper'));
$('#' + ident + ' ' + '.wall-item-like').replaceWith($(this).find('.wall-item-like'));
$('#' + ident + ' ' + '.wall-item-dislike').replaceWith($(this).find('.wall-item-dislike'));
- $('#' + ident + ' ' + '.my-comment-photo').each(function() {
- $(this).attr('src',$(this).attr('dst'));
- });
-
-
+ $('#' + ident + ' ' + '.my-comment-photo').each(function() {
+ $(this).attr('src',$(this).attr('dst'));
+ });
}
prev = ident;
});
$('.like-rotator').hide();
+ if(commentBusy) {
+ commentBusy = false;
+ $('body').css('cursor', 'auto');
+ }
});
-
}
function imgbright(node) {
- $(node).attr("src",$(node).attr("src").replace('hide','show'));
- $(node).css('width',24);
- $(node).css('height',24);
+ $(node).removeClass("drophide").addClass("drop");
}
function imgdull(node) {
- $(node).attr("src",$(node).attr("src").replace('show','hide'));
- $(node).css('width',16);
- $(node).css('height',16);
+ $(node).removeClass("drop").addClass("drophide");
}
// Since our ajax calls are asynchronous, we will give a few
@@ -215,6 +235,8 @@
}
function post_comment(id) {
+ commentBusy = true;
+ $('body').css('cursor', 'wait');
$.post(
"item",
$("#comment-edit-form-" + id).serialize(),
@@ -231,10 +253,49 @@
if(data.reload) {
window.location.href=data.reload;
}
-
},
"json"
);
return false;
}
+
+ function bin2hex(s){
+ // Converts the binary representation of data to hex
+ //
+ // version: 812.316
+ // discuss at: http://phpjs.org/functions/bin2hex
+ // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
+ // + bugfixed by: Onno Marsman
+ // + bugfixed by: Linuxworld
+ // * example 1: bin2hex('Kev');
+ // * returns 1: '4b6576'
+ // * example 2: bin2hex(String.fromCharCode(0x00));
+ // * returns 2: '00'
+ var v,i, f = 0, a = [];
+ s += '';
+ f = s.length;
+
+ for (i = 0; i<f; i++) {
+ a[i] = s.charCodeAt(i).toString(16).replace(/^([\da-f])$/,"0$1");
+ }
+
+ return a.join('');
+ }
+
+ function groupChangeMember(gid,cid) {
+ $('body .fakelink').css('cursor', 'wait');
+ $.get('group/' + gid + '/' + cid, function(data) {
+ $('#group-update-wrapper').html(data);
+ $('body .fakelink').css('cursor', 'auto');
+ });
+ }
+
+ function profChangeMember(gid,cid) {
+ $('body .fakelink').css('cursor', 'wait');
+ $.get('profperm/' + gid + '/' + cid, function(data) {
+ $('#prof-update-wrapper').html(data);
+ $('body .fakelink').css('cursor', 'auto');
+ });
+ }
+
diff --git a/include/nav.php b/include/nav.php
index 4104cf3cf..66fdbc49b 100644
--- a/include/nav.php
+++ b/include/nav.php
@@ -27,24 +27,23 @@ function nav(&$a) {
$myident = ((is_array($a->user) && isset($a->user['nickname'])) ? $a->user['nickname'] . '@' : '');
- $a->page['nav'] .= '<div id="site-location">' . $myident . substr($a->get_baseurl(),strpos($a->get_baseurl(),'//') + 2 ) . '</div>';
+ $sitelocation = $myident . substr($a->get_baseurl(),strpos($a->get_baseurl(),'//') + 2 );
+ // nav links: array of array('href', 'text', 'extra css classes')
+ $nav = Array();
+
/**
* Display login or logout
*/
if(local_user()) {
- $a->page['nav'] .= '<a id="nav-logout-link" class="nav-link" href="logout">' . t('Logout') . "</a>\r\n";
+ $nav['logout'] = Array('logout',t('Logout'), "");
}
else {
- $a->page['nav'] .= '<a id="nav-login-link" class="nav-login-link';
- if ($a->module == 'login') { $a->page['nav'] .= ' nav-selected'; }
-
- $a->page['nav'] .= '" href="login">' . t('Login') . "</a>\r\n";
+ $nav['login'] = Array('login',t('Login'), ($a->module == 'login'?'nav-selected':''));
}
- $a->page['nav'] .= "<span id=\"nav-link-wrapper\" >\r\n";
/**
* "Home" should also take you home from an authenticated remote profile connection
@@ -53,18 +52,22 @@ function nav(&$a) {
$homelink = ((x($_SESSION,'visitor_home')) ? $_SESSION['visitor_home'] : '');
if(($a->module != 'home') && (! (local_user())))
- $a->page['nav'] .= '<a id="nav-home-link" class="nav-commlink" href="' . $homelink . '">' . t('Home') . "</a>\r\n";
+ $nav['home'] = array($homelink, t('Home'), "");
if(($a->config['register_policy'] == REGISTER_OPEN) && (! local_user()) && (! remote_user()))
- $a->page['nav'] .= '<a id="nav-register-link" class="nav-commlink" href="register" >'
- . t('Register') . "</a>\r\n";
+ $nav['register'] = array('register',t('Register'), "");
+
+ $help_url = $a->get_baseurl() . '/help';
+
+ if(! get_config('system','hide-help'))
+ $nav['help'] = array($help_url, t('Help'), "");
+
- if(strlen($a->apps)) {
- $a->page['nav'] .= '<a id="nav-apps-link" class="nav-link" href="apps">' . t('Apps') . "</a>\r\n";
- }
- $a->page['nav'] .= '<a id="nav-search-link" class="nav-link" href="search">' . t('Search') . "</a>\r\n";
+ $nav['apps'] = array('apps', t('Apps'), "");
+
+ $nav['search'] = array('search', t('Search'), "");
$gdirpath = 'directory';
@@ -74,7 +77,7 @@ function nav(&$a) {
$gdirpath = $gdir;
}
- $a->page['nav'] .= '<a id="nav-directory-link" class="nav-link" href="' . $gdirpath . '">' . t('Directory') . "</a>\r\n";
+ $nav['directory'] = array($gdirpath, t('Directory'), "");
/**
*
@@ -84,36 +87,30 @@ function nav(&$a) {
if(local_user()) {
- $a->page['nav'] .= '<a id="nav-network-link" class="nav-commlink" href="network">' . t('Network')
- . '</a><span id="net-update" class="nav-ajax-left"></span>' . "\r\n";
+ $nav['network'] = array('network', t('Network'), "");
+
+ $nav['home'] = array('profile/' . $a->user['nickname'], t('Home'), "");
- $a->page['nav'] .= '<a id="nav-home-link" class="nav-commlink" href="profile/' . $a->user['nickname'] . '">'
- . t('Home') . '</a><span id="home-update" class="nav-ajax-left"></span>' . "\r\n";
/* only show friend requests for normal pages. Other page types have automatic friendship. */
if($_SESSION['page_flags'] == PAGE_NORMAL) {
- $a->page['nav'] .= '<a id="nav-notify-link" class="nav-commlink" href="notifications">' . t('Notifications')
- . '</a><span id="notify-update" class="nav-ajax-left"></span>' . "\r\n";
+ $nav['notifications'] = array('notifications', t('Notifications'), "");
}
- $a->page['nav'] .= '<a id="nav-messages-link" class="nav-commlink" href="message">' . t('Messages')
- . '</a><span id="mail-update" class="nav-ajax-left"></span>' . "\r\n";
+ $nav['messages'] = array('message', t('Messages'), "");
if(is_array($a->identities) && count($a->identities) > 1) {
- $a->page['nav'] .= '<a id="nav-manage-link" class="nav-commlink" href="manage">' . t('Manage') . '</a>' . "\r\n";
+ $nav['manage'] = array('manage', t('Manage'), "");
}
- $a->page['nav'] .= '<a id="nav-settings-link" class="nav-link" href="settings">' . t('Settings') . "</a>\r\n";
-
- $a->page['nav'] .= '<a id="nav-profiles-link" class="nav-link" href="profiles">' . t('Profiles') . "</a>\r\n";
-
- $a->page['nav'] .= '<a id="nav-contacts-link" class="nav-link" href="contacts">' . t('Contacts') . "</a>\r\n";
+ $nav['settings'] = array('settings', t('Settings'),"");
+ $nav['profiles'] = array('profiles', t('Profiles'),"");
+ $nav['contacts'] = array('contacts', t('Contacts'),"");
}
- $a->page['nav'] .= "</span>\r\n<span id=\"nav-end\"></span>\r\n";
/**
*
@@ -124,10 +121,17 @@ function nav(&$a) {
$banner = get_config('system','banner');
if($banner === false)
- $banner .= '<a href="http://friendika.com"><img id="logo-img" src="images/friendika-32.png" alt="logo" /></a><span id="logo-text"><a href="http://friendika.com">Friendika</a></span>';
+ $banner .= '<a href="http://project.friendika.com"><img id="logo-img" src="images/friendika-32.png" alt="logo" /></a><span id="logo-text"><a href="http://project.friendika.com">Friendika</a></span>';
+
+ $tpl = get_markup_template('nav.tpl');
- $a->page['nav'] .= '<span id="banner">' . $banner . '</span>';
+ $a->page['nav'] .= replace_macros($tpl, array(
+ '$langselector' => lang_selector(),
+ '$sitelocation' => $sitelocation,
+ '$nav' => $nav,
+ '$banner' => $banner,
+ ));
call_hooks('page_header', $a->page['nav']);
diff --git a/include/notifier.php b/include/notifier.php
index 648a07062..db2542849 100644
--- a/include/notifier.php
+++ b/include/notifier.php
@@ -20,6 +20,8 @@ function notifier_run($argv, $argc){
require_once('include/items.php');
require_once('include/bbcode.php');
+ load_hooks();
+
if($argc < 3)
return;
@@ -40,6 +42,7 @@ function notifier_run($argv, $argc){
break;
}
+ $expire = false;
$top_level = false;
$recipients = array();
$url_recipients = array();
@@ -57,10 +60,21 @@ function notifier_run($argv, $argc){
$item = $message[0];
}
+ elseif($cmd === 'expire') {
+ $expire = true;
+ $items = q("SELECT * FROM `item` WHERE `uid` = %d AND `wall` = 1
+ AND `deleted` = 1 AND `changed` > UTC_TIMESTAMP - INTERVAL 10 MINUTE",
+ intval($item_id)
+ );
+ $uid = $item_id;
+ $item_id = 0;
+ if(! count($items))
+ return;
+ }
else {
// find ancestors
- $r = q("SELECT `parent`, `uid`, `edited` FROM `item` WHERE `id` = %d LIMIT 1",
+ $r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1",
intval($item_id)
);
@@ -68,6 +82,7 @@ function notifier_run($argv, $argc){
return;
}
+ $parent_item = $r[0];
$parent_id = intval($r[0]['parent']);
$uid = $r[0]['uid'];
$updated = $r[0]['edited'];
@@ -76,11 +91,10 @@ function notifier_run($argv, $argc){
intval($parent_id)
);
- if(! count($items)){
+ if(! count($items)) {
return;
}
-
// avoid race condition with deleting entries
if($items[0]['deleted']) {
@@ -98,11 +112,11 @@ function notifier_run($argv, $argc){
intval($uid)
);
- if(count($r))
- $owner = $r[0];
- else {
+ if(! count($r))
return;
- }
+
+ $owner = $r[0];
+
$hub = get_config('system','huburl');
// If this is a public conversation, notify the feed hub
@@ -117,7 +131,7 @@ function notifier_run($argv, $argc){
$parent = $items[0];
- if($parent['type'] === 'remote') {
+ if($parent['type'] === 'remote' && (! $expire)) {
// local followup to remote post
$followup = true;
$notify_hub = false; // not public
@@ -177,8 +191,8 @@ function notifier_run($argv, $argc){
$contacts = $r;
}
- $feed_template = load_view_file('view/atom_feed.tpl');
- $mail_template = load_view_file('view/atom_mail.tpl');
+ $feed_template = get_markup_template('atom_feed.tpl');
+ $mail_template = get_markup_template('atom_mail.tpl');
$atom = '';
$slaps = array();
@@ -235,6 +249,7 @@ function notifier_run($argv, $argc){
}
else {
foreach($items as $item) {
+
if(! $item['parent'])
continue;
@@ -242,9 +257,9 @@ function notifier_run($argv, $argc){
if(! $contact)
continue;
- $atom .= atom_entry($item,'text',$contact,$owner,true);
+ $atom .= atom_entry($item,'text',$contact,$owner,true);
- if(($top_level) && ($notify_hub) && ($item['author-link'] === $item['owner-link']))
+ if(($top_level) && ($notify_hub) && ($item['author-link'] === $item['owner-link']) && (! $expire))
$slaps[] = atom_entry($item,'html',$contact,$owner,true);
}
}
@@ -255,12 +270,30 @@ function notifier_run($argv, $argc){
logger('notifier: slaps: ' . print_r($slaps,true), LOGGER_DATA);
+ // If this is a public message and pubmail is set on the parent, include all your email contacts
+
+ $mail_disabled = ((function_exists('imap_open') && (! get_config('system','imap_disabled'))) ? 0 : 1);
+
+ if(! $mail_disabled) {
+ if((! strlen($parent_item['allow_cid'])) && (! strlen($parent_item['allow_gid']))
+ && (! strlen($parent_item['deny_cid'])) && (! strlen($parent_item['deny_gid']))
+ && (intval($parent_item['pubmail']))) {
+ $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `network` = '%s'",
+ intval($uid),
+ dbesc(NETWORK_MAIL)
+ );
+ if(count($r)) {
+ foreach($r as $rr)
+ $recipients[] = $rr['id'];
+ }
+ }
+ }
+
if($followup)
$recip_str = $parent['contact-id'];
else
$recip_str = implode(', ', $recipients);
-
$r = q("SELECT * FROM `contact` WHERE `id` IN ( %s ) AND `blocked` = 0 AND `pending` = 0 ",
dbesc($recip_str)
);
@@ -319,7 +352,7 @@ function notifier_run($argv, $argc){
// only send salmon if public - e.g. if it's ok to notify
// a public hub, it's ok to send a salmon
- if(count($slaps) && $notify_hub) {
+ if((count($slaps)) && ($notify_hub) && (! $expire)) {
logger('notifier: slapdelivery: ' . $contact['name']);
foreach($slaps as $slappy) {
if($contact['notify']) {
@@ -340,8 +373,82 @@ function notifier_run($argv, $argc){
}
break;
case 'mail':
+
+ // WARNING: does not currently convert to RFC2047 header encodings, etc.
+
+ $addr = $contact['addr'];
+ if(! strlen($addr))
+ break;
+
+ if($cmd === 'wall-new' || $cmd === 'comment-new') {
+
+ $it = null;
+ if($cmd === 'wall-new')
+ $it = $items[0];
+ else {
+ $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1",
+ intval($argv[2]),
+ intval($uid)
+ );
+ if(count($r))
+ $it = $r[0];
+ }
+ if(! $it)
+ break;
+
+
+
+ $local_user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1",
+ intval($uid)
+ );
+ if(! count($local_user))
+ break;
+
+ $reply_to = '';
+ $r1 = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1",
+ intval($uid)
+ );
+ if($r1 && $r1[0]['reply_to'])
+ $reply_to = $r1[0]['reply_to'];
+
+ $subject = (($it['title']) ? $it['title'] : t("\x28no subject\x29")) ;
+ $headers = 'From: ' . $local_user[0]['username'] . ' <' . $local_user[0]['email'] . '>' . "\n";
+
+ if($reply_to)
+ $headers .= 'Reply-to: ' . $reply_to . "\n";
+
+ $headers .= 'Message-id: <' . $it['uri'] . '>' . "\n";
+
+ if($it['uri'] !== $it['parent-uri']) {
+ $header .= 'References: <' . $it['parent-uri'] . '>' . "\n";
+ if(! strlen($it['title'])) {
+ $r = q("SELECT `title` FROM `item` WHERE `parent-uri` = '%s' LIMIT 1",
+ dbesc($it['parent-uri'])
+ );
+ if(count($r)) {
+ $subtitle = $r[0]['title'];
+ if($subtitle) {
+ if(strncasecmp($subtitle,'RE:',3))
+ $subject = $subtitle;
+ else
+ $subject = 'Re: ' . $subtitle;
+ }
+ }
+ }
+ }
+
+ $headers .= 'MIME-Version: 1.0' . "\n";
+ $headers .= 'Content-Type: text/html; charset=UTF-8' . "\n";
+ $headers .= 'Content-Transfer-Encoding: 8bit' . "\n\n";
+ $html = prepare_body($it);
+ $message = '<html><body>' . $html . '</body></html>';
+ logger('notifier: email delivery to ' . $addr);
+ mail($addr, $subject, $message, $headers);
+ }
+ break;
case 'dspr':
case 'feed':
+ case 'face':
default:
break;
}
@@ -350,7 +457,7 @@ function notifier_run($argv, $argc){
// send additional slaps to mentioned remote tags (@foo@example.com)
- if($slap && count($url_recipients) && $followup && $notify_hub) {
+ if($slap && count($url_recipients) && $followup && $notify_hub && (! $expire)) {
foreach($url_recipients as $url) {
if($url) {
logger('notifier: urldelivery: ' . $url);
diff --git a/include/pgettext.php b/include/pgettext.php
new file mode 100644
index 000000000..2ffee70bc
--- /dev/null
+++ b/include/pgettext.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * translation support
+ */
+
+// load string translation table for alternate language
+
+if(! function_exists('load_translation_table')) {
+function load_translation_table($lang) {
+ global $a;
+
+ if(file_exists("view/$lang/strings.php"))
+ include("view/$lang/strings.php");
+}}
+
+// translate string if translation exists
+
+if(! function_exists('t')) {
+function t($s) {
+
+ $a = get_app();
+
+ if(x($a->strings,$s)) {
+ $t = $a->strings[$s];
+ return is_array($t)?$t[0]:$t;
+ }
+ return $s;
+}}
+
+if(! function_exists('tt')){
+function tt($singular, $plural, $count){
+
+ $a = get_app();
+
+ if(x($a->strings,$singular)) {
+ $t = $a->strings[$singular];
+ $k = string_plural_select($count);
+ return is_array($t)?$t[$k]:$t;
+ }
+
+ if ($count!=1){
+ return $plural;
+ } else {
+ return $singular;
+ }
+}} \ No newline at end of file
diff --git a/include/poller.php b/include/poller.php
index a093190a6..7490bfa81 100644
--- a/include/poller.php
+++ b/include/poller.php
@@ -1,4 +1,5 @@
<?php
+
require_once("boot.php");
function poller_run($argv, $argc){
@@ -15,20 +16,35 @@ function poller_run($argv, $argc){
unset($db_host, $db_user, $db_pass, $db_data);
};
+
require_once('session.php');
require_once('datetime.php');
require_once('simplepie/simplepie.inc');
require_once('include/items.php');
require_once('include/Contact.php');
+ require_once('include/email.php');
$a->set_baseurl(get_config('system','url'));
+ load_hooks();
+
logger('poller: start');
// run queue delivery process in the background
proc_run('php',"include/queue.php");
+ // once daily run expire in background
+
+ $d1 = get_config('system','last_expire_day');
+ $d2 = intval(datetime_convert('UTC','UTC','now','d'));
+
+ if($d2 != intval($d1)) {
+ set_config('system','last_expire_day',$d2);
+ proc_run('php','include/expire.php');
+ }
+
+
// clear old cache
q("DELETE FROM `cache` WHERE `updated` < '%s'",
dbesc(datetime_convert('UTC','UTC',"now - 30 days")));
@@ -47,10 +63,12 @@ function poller_run($argv, $argc){
$sql_extra = (($manual_id) ? " AND `id` = $manual_id " : "");
+ reload_plugins();
+
$d = datetime_convert();
+
call_hooks('cron', $d);
- reload_plugins();
$contacts = q("SELECT `id` FROM `contact`
WHERE ( `rel` = %d OR `rel` = %d ) AND `poll` != ''
@@ -74,6 +92,9 @@ function poller_run($argv, $argc){
continue;
foreach($res as $contact) {
+
+ $xml = false;
+
if($manual_id)
$contact['last-update'] = '0000-00-00 00:00:00';
@@ -147,25 +168,29 @@ function poller_run($argv, $argc){
: datetime_convert('UTC','UTC',$contact['last-update'], ATOM_TIME)
);
- if($contact['network'] === 'dfrn') {
+ if($contact['network'] === NETWORK_DFRN) {
$idtosend = $orig_id = (($contact['dfrn-id']) ? $contact['dfrn-id'] : $contact['issued-id']);
if(intval($contact['duplex']) && $contact['dfrn-id'])
$idtosend = '0:' . $orig_id;
if(intval($contact['duplex']) && $contact['issued-id'])
- $idtosend = '1:' . $orig_id;
+ $idtosend = '1:' . $orig_id;
+
+ // they have permission to write to us. We already filtered this in the contact query.
+ $perm = 'rw';
$url = $contact['poll'] . '?dfrn_id=' . $idtosend
. '&dfrn_version=' . DFRN_PROTOCOL_VERSION
- . '&type=data&last_update=' . $last_update ;
+ . '&type=data&last_update=' . $last_update
+ . '&perm=' . $perm ;
- $xml = fetch_url($url);
+ $handshake_xml = fetch_url($url);
- logger('poller: handshake with url ' . $url . ' returns xml: ' . $xml, LOGGER_DATA);
+ logger('poller: handshake with url ' . $url . ' returns xml: ' . $handshake_xml, LOGGER_DATA);
- if(! $xml) {
+ if(! $handshake_xml) {
logger("poller: $url appears to be dead - marking for death ");
// dead connection - might be a transient event, or this might
// mean the software was uninstalled or the domain expired.
@@ -182,7 +207,7 @@ function poller_run($argv, $argc){
continue;
}
- if(! strstr($xml,'<?xml')) {
+ if(! strstr($handshake_xml,'<?xml')) {
logger('poller: response from ' . $url . ' did not contain XML.');
$r = q("UPDATE `contact` SET `last-update` = '%s' WHERE `id` = %d LIMIT 1",
dbesc(datetime_convert()),
@@ -192,7 +217,7 @@ function poller_run($argv, $argc){
}
- $res = simplexml_load_string($xml);
+ $res = parse_xml_string($handshake_xml);
if(intval($res->status) == 1) {
logger("poller: $url replied status 1 - marking for death ");
@@ -239,56 +264,181 @@ function poller_run($argv, $argc){
$final_dfrn_id = substr($final_dfrn_id,2);
if($final_dfrn_id != $orig_id) {
-
+ logger('poller: ID did not decode: ' . $contact['id'] . ' orig: ' . $orig_id . ' final: ' . $final_dfrn_id);
// did not decode properly - cannot trust this site
continue;
}
$postvars['dfrn_id'] = $idtosend;
$postvars['dfrn_version'] = DFRN_PROTOCOL_VERSION;
+ $postvars['perm'] = 'rw';
$xml = post_url($contact['poll'],$postvars);
}
- else {
+ elseif(($contact['network'] === NETWORK_OSTATUS)
+ || ($contact['network'] === NETWORK_DIASPORA)
+ || ($contact['network'] === NETWORK_FEED) ) {
+
+ // Upgrading DB fields from an older Friendika version
+ // Will only do this once per notify-enabled OStatus contact
- // $contact['network'] !== 'dfrn'
+ if(($contact['notify']) && (! $contact['writable'])) {
+ q("UPDATE `contact` SET `writable` = 1 WHERE `id` = %d LIMIT 1",
+ intval($contact['id'])
+ );
+ }
$xml = fetch_url($contact['poll']);
}
+ elseif($contact['network'] === NETWORK_MAIL) {
- logger('poller: received xml : ' . $xml, LOGGER_DATA);
+ $mail_disabled = ((function_exists('imap_open') && (! get_config('system','imap_disabled'))) ? 0 : 1);
+ if($mail_disabled)
+ continue;
- if(! strstr($xml,'<?xml')) {
- logger('poller: post_handshake: response from ' . $url . ' did not contain XML.');
- $r = q("UPDATE `contact` SET `last-update` = '%s' WHERE `id` = %d LIMIT 1",
- dbesc(datetime_convert()),
- intval($contact['id'])
+ $mbox = null;
+ $x = q("SELECT `prvkey` FROM `user` WHERE `uid` = %d LIMIT 1",
+ intval($importer_uid)
);
- continue;
+ $mailconf = q("SELECT * FROM `mailacct` WHERE `server` != '' AND `uid` = %d LIMIT 1",
+ intval($importer_uid)
+ );
+ if(count($x) && count($mailconf)) {
+ $mailbox = construct_mailbox_name($mailconf[0]);
+ $password = '';
+ openssl_private_decrypt(hex2bin($mailconf[0]['pass']),$password,$x[0]['prvkey']);
+ $mbox = email_connect($mailbox,$mailconf[0]['user'],$password);
+ unset($password);
+ if($mbox) {
+ q("UPDATE `mailacct` SET `last_check` = '%s' WHERE `id` = %d AND `uid` = %d LIMIT 1",
+ dbesc(datetime_convert()),
+ intval($mailconf[0]['id']),
+ intval($importer_uid)
+ );
+ }
+ }
+ if($mbox) {
+
+ $msgs = email_poll($mbox,$contact['addr']);
+
+ if(count($msgs)) {
+ foreach($msgs as $msg_uid) {
+ $datarray = array();
+ $meta = email_msg_meta($mbox,$msg_uid);
+ $headers = email_msg_headers($mbox,$msg_uid);
+
+ // look for a 'references' header and try and match with a parent item we have locally.
+
+ $raw_refs = ((x($headers,'references')) ? str_replace("\t",'',$headers['references']) : '');
+ $datarray['uri'] = trim($meta->message_id,'<>');
+
+ if($raw_refs) {
+ $refs_arr = explode(' ', $raw_refs);
+ if(count($refs_arr)) {
+ for($x = 0; $x < count($refs_arr); $x ++)
+ $refs_arr[$x] = "'" . str_replace(array('<','>',' '),array('','',''),dbesc($refs_arr[$x])) . "'";
+ }
+ $qstr = implode(',',$refs_arr);
+ $r = q("SELECT `uri` , `parent-uri` FROM `item` WHERE `uri` IN ( $qstr ) AND `uid` = %d LIMIT 1",
+ intval($importer_uid)
+ );
+ if(count($r))
+ $datarray['parent-uri'] = $r[0]['uri'];
+ }
+
+
+ if(! x($datarray,'parent-uri'))
+ $datarray['parent-uri'] = $datarray['uri'];
+
+ // Have we seen it before?
+ $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `uri` = '%s' LIMIT 1",
+ intval($importer_uid),
+ dbesc($datarray['uri'])
+ );
+
+ if(count($r)) {
+ if($meta->deleted && ! $r[0]['deleted']) {
+ q("UPDATE `item` SET `deleted` = 1, `changed` = '%s' WHERE `id` = %d LIMIT 1",
+ dbesc(datetime_convert()),
+ intval($r[0]['id'])
+ );
+ }
+ continue;
+ }
+ $datarray['title'] = notags(trim($meta->subject));
+ $datarray['created'] = datetime_convert('UTC','UTC',$meta->date);
+
+ $r = email_get_msg($mbox,$msg_uid);
+ if(! $r)
+ continue;
+ $datarray['body'] = escape_tags($r['body']);
+
+ // some mailing lists have the original author as 'from' - add this sender info to msg body.
+ // todo: adding a gravatar for the original author would be cool
+
+ if(! stristr($meta->from,$contact['addr']))
+ $datarray['body'] = t('From: ') . escape_tags($meta->from) . "\n\n" . $datarray['body'];
+
+ $datarray['uid'] = $importer_uid;
+ $datarray['contact-id'] = $contact['id'];
+ if($datarray['parent-uri'] === $datarray['uri'])
+ $datarray['private'] = 1;
+ $datarray['author-name'] = $contact['name'];
+ $datarray['author-link'] = 'mailbox';
+ $datarray['author-avatar'] = $contact['photo'];
+
+ $stored_item = item_store($datarray);
+ q("UPDATE `item` SET `last-child` = 0 WHERE `parent-uri` = '%s' AND `uid` = %d",
+ dbesc($datarray['parent-uri']),
+ intval($importer_uid)
+ );
+ q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d LIMIT 1",
+ intval($stored_item)
+ );
+ }
+ }
+
+ imap_close($mbox);
+ }
+ }
+ elseif($contact['network'] === NETWORK_FACEBOOK) {
+ // TODO: work in progress
}
- consume_feed($xml,$importer,$contact,$hub,1);
+ if($xml) {
+ logger('poller: received xml : ' . $xml, LOGGER_DATA);
- // do it twice. Ensures that children of parents which may be later in the stream aren't tossed
+ if(! strstr($xml,'<?xml')) {
+ logger('poller: post_handshake: response from ' . $url . ' did not contain XML.');
+ $r = q("UPDATE `contact` SET `last-update` = '%s' WHERE `id` = %d LIMIT 1",
+ dbesc(datetime_convert()),
+ intval($contact['id'])
+ );
+ continue;
+ }
- consume_feed($xml,$importer,$contact,$hub,1);
+ consume_feed($xml,$importer,$contact,$hub,1, true);
- if((strlen($hub)) && ($hub_update)
- && (($contact['rel'] == REL_BUD) || (($contact['network'] === 'stat') && (! $contact['readonly'])))) {
- logger('poller: subscribing to hub(s) : ' . $hub . ' contact name : ' . $contact['name'] . ' local user : ' . $importer['name']);
- $hubs = explode(',', $hub);
- if(count($hubs)) {
- foreach($hubs as $h) {
- $h = trim($h);
- if(! strlen($h))
- continue;
- subscribe_to_hub($h,$importer,$contact);
+ // do it twice. Ensures that children of parents which may be later in the stream aren't tossed
+
+ consume_feed($xml,$importer,$contact,$hub,1);
+
+
+ if((strlen($hub)) && ($hub_update) && (($contact['rel'] == REL_BUD) || (($contact['network'] === NETWORK_OSTATUS) && (! $contact['readonly'])))) {
+ logger('poller: subscribing to hub(s) : ' . $hub . ' contact name : ' . $contact['name'] . ' local user : ' . $importer['name']);
+ $hubs = explode(',', $hub);
+ if(count($hubs)) {
+ foreach($hubs as $h) {
+ $h = trim($h);
+ if(! strlen($h))
+ continue;
+ subscribe_to_hub($h,$importer,$contact);
+ }
}
}
}
-
$updated = datetime_convert();
$r = q("UPDATE `contact` SET `last-update` = '%s', `success_update` = '%s' WHERE `id` = %d LIMIT 1",
@@ -300,6 +450,7 @@ function poller_run($argv, $argc){
// loop - next contact
}
}
+
return;
}
diff --git a/include/profile_advanced.php b/include/profile_advanced.php
new file mode 100644
index 000000000..c1dfad66f
--- /dev/null
+++ b/include/profile_advanced.php
@@ -0,0 +1,258 @@
+<?php
+
+function advanced_profile(&$a) {
+
+$o .= '';
+
+$o .= '<h2>' . t('Profile') . '</h2>';
+
+if($a->profile['name']) {
+ $lbl_fullname = t('Full Name:');
+ $fullname = $a->profile['name'];
+
+$o .= <<< EOT
+<div id="advanced-profile-name-wrapper" >
+<div id="advanced-profile-name-text">$lbl_fullname</div>
+<div id="advanced-profile-name">$fullname</div>
+</div>
+<div id="advanced-profile-name-end"></div>
+EOT;
+}
+
+if($a->profile['gender']) {
+ $lbl_gender = t('Gender:');
+ $gender = $a->profile['gender'];
+
+$o .= <<< EOT
+<div id="advanced-profile-gender-wrapper" >
+<div id="advanced-profile-gender-text">$lbl_gender</div>
+<div id="advanced-profile-gender">$gender</div>
+</div>
+<div id="advanced-profile-gender-end"></div>
+EOT;
+}
+
+if(($a->profile['dob']) && ($a->profile['dob'] != '0000-00-00')) {
+ $lbl_birthday = t('Birthday:');
+
+$o .= <<< EOT
+<div id="advanced-profile-dob-wrapper" >
+<div id="advanced-profile-dob-text">$lbl_birthday</div>
+EOT;
+
+// If no year, add an arbitrary one so just we can parse the month and day.
+
+$year_bd_format = t('j F, Y');
+$short_bd_format = t('j F');
+
+$o .= '<div id="advanced-profile-dob">'
+ . ((intval($a->profile['dob']))
+ ? day_translate(datetime_convert('UTC','UTC',$a->profile['dob'] . ' 00:00 +00:00',$year_bd_format))
+ : day_translate(datetime_convert('UTC','UTC','2001-' . substr($a->profile['dob'],6) . ' 00:00 +00:00',$short_bd_format)))
+ . "</div>\r\n</div>";
+
+$o .= '<div id="advanced-profile-dob-end"></div>';
+
+}
+
+if($age = age($a->profile['dob'],$a->profile['timezone'],'')) {
+ $lbl_age = t('Age:');
+$o .= <<< EOT
+<div id="advanced-profile-age-wrapper" >
+<div id="advanced-profile-age-text">$lbl_age</div>
+<div id="advanced-profile-age">$age</div>
+</div>
+<div id="advanced-profile-age-end"></div>
+EOT;
+}
+
+if($a->profile['marital']) {
+ $lbl_marital = t('<span class="heart">&hearts;</span> Status:');
+ $marital = $a->profile['marital'];
+
+$o .= <<< EOT
+<div id="advanced-profile-marital-wrapper" >
+<div id="advanced-profile-marital-text">$lbl_marital</div>
+<div id="advanced-profile-marital">$marital</div>
+EOT;
+
+if($a->profile['with']) {
+ $with = $a->profile['with'];
+ $o .= "<div id=\"advanced-profile-with\">($with)</div>";
+}
+$o .= <<< EOT
+</div>
+<div id="advanced-profile-marital-end"></div>
+EOT;
+}
+
+if($a->profile['sexual']) {
+ $lbl_sexual = t('Sexual Preference:');
+ $sexual = $a->profile['sexual'];
+
+$o .= <<< EOT
+<div id="advanced-profile-sexual-wrapper" >
+<div id="advanced-profile-sexual-text">$lbl_sexual</div>
+<div id="advanced-profile-sexual">$sexual</div>
+</div>
+<div id="advanced-profile-sexual-end"></div>
+EOT;
+}
+
+if($a->profile['homepage']) {
+ $lbl_homepage = t('Homepage:');
+ $homepage = linkify($a->profile['homepage']);
+$o .= <<< EOT
+<div id="advanced-profile-homepage-wrapper" >
+<div id="advanced-profile-homepage-text">$lbl_homepage</div>
+<div id="advanced-profile-homepage">$homepage</div>
+</div>
+<div id="advanced-profile-homepage-end"></div>
+EOT;
+}
+
+if($a->profile['politic']) {
+ $lbl_politic = t('Political Views:');
+ $politic = $a->profile['politic'];
+$o .= <<< EOT
+<div id="advanced-profile-politic-wrapper" >
+<div id="advanced-profile-politic-text">$lbl_politic</div>
+<div id="advanced-profile-politic">$politic</div>
+</div>
+<div id="advanced-profile-politic-end"></div>
+EOT;
+}
+
+if($a->profile['religion']) {
+ $lbl_religion = t('Religion:');
+ $religion = $a->profile['religion'];
+$o .= <<< EOT
+<div id="advanced-profile-religion-wrapper" >
+<div id="advanced-profile-religion-text">$lbl_religion</div>
+<div id="advanced-profile-religion">$religion</div>
+</div>
+<div id="advanced-profile-religion-end"></div>
+EOT;
+}
+if($txt = prepare_text($a->profile['about'])) {
+ $lbl_about = t('About:');
+$o .= <<< EOT
+<div id="advanced-profile-about-wrapper" >
+<div id="advanced-profile-about-text">$lbl_about</div>
+<br />
+<div id="advanced-profile-about">$txt</div>
+</div>
+<div id="advanced-profile-about-end"></div>
+EOT;
+}
+
+if($txt = prepare_text($a->profile['interest'])) {
+ $lbl_interests = t('Hobbies/Interests:');
+$o .= <<< EOT
+<div id="advanced-profile-interest-wrapper" >
+<div id="advanced-profile-interest-text">$lbl_interests</div>
+<br />
+<div id="advanced-profile-interest">$txt</div>
+</div>
+<div id="advanced-profile-interest-end"></div>
+EOT;
+}
+
+if($txt = prepare_text($a->profile['contact'])) {
+ $lbl_contact = t('Contact information and Social Networks:');
+$o .= <<< EOT
+<div id="advanced-profile-contact-wrapper" >
+<div id="advanced-profile-contact-text">$lbl_contact</div>
+<br />
+<div id="advanced-profile-contact">$txt</div>
+</div>
+<div id="advanced-profile-contact-end"></div>
+EOT;
+}
+
+if($txt = prepare_text($a->profile['music'])) {
+ $lbl_music = t('Musical interests:');
+$o .= <<< EOT
+<div id="advanced-profile-music-wrapper" >
+<div id="advanced-profile-music-text">$lbl_music</div>
+<br />
+<div id="advanced-profile-music">$txt</div>
+</div>
+<div id="advanced-profile-music-end"></div>
+EOT;
+}
+
+if($txt = prepare_text($a->profile['book'])) {
+ $lbl_book = t('Books, literature:');
+$o .= <<< EOT
+<div id="advanced-profile-book-wrapper" >
+<div id="advanced-profile-book-text">$lbl_book</div>
+<br />
+<div id="advanced-profile-book">$txt</div>
+</div>
+<div id="advanced-profile-book-end"></div>
+EOT;
+}
+
+if($txt = prepare_text($a->profile['tv'])) {
+ $lbl_tv = t('Television:');
+$o .= <<< EOT
+<div id="advanced-profile-tv-wrapper" >
+<div id="advanced-profile-tv-text">$lbl_tv</div>
+<br />
+<div id="advanced-profile-tv">$txt</div>
+</div>
+<div id="advanced-profile-tv-end"></div>
+EOT;
+}
+
+if($txt = prepare_text($a->profile['film'])) {
+ $lbl_film = t('Film/dance/culture/entertainment:');
+$o .= <<< EOT
+<div id="advanced-profile-film-wrapper" >
+<div id="advanced-profile-film-text">$lbl_film</div>
+<br />
+<div id="advanced-profile-film">$txt</div>
+</div>
+<div id="advanced-profile-film-end"></div>
+EOT;
+}
+
+if($txt = prepare_text($a->profile['romance'])) {
+ $lbl_romance = t('Love/Romance:');
+$o .= <<< EOT
+<div id="advanced-profile-romance-wrapper" >
+<div id="advanced-profile-romance-text">$lbl_romance</div>
+<br />
+<div id="advanced-profile-romance">$txt</div>
+</div>
+<div id="advanced-profile-romance-end"></div>
+EOT;
+}
+
+if($txt = prepare_text($a->profile['work'])) {
+ $lbl_work = t('Work/employment:');
+$o .= <<< EOT
+<div id="advanced-profile-work-wrapper" >
+<div id="advanced-profile-work-text">$lbl_work</div>
+<br />
+<div id="advanced-profile-work">$txt</div>
+</div>
+<div id="advanced-profile-work-end"></div>
+EOT;
+}
+
+if($txt = prepare_text($a->profile['education'])) {
+ $lbl_education = t('School/education:');
+$o .= <<< EOT
+<div id="advanced-profile-education-wrapper" >
+<div id="advanced-profile-education-text">$lbl_education</div>
+<br />
+<div id="advanced-profile-education">$txt</div>
+</div>
+<div id="advanced-profile-education-end"></div>
+EOT;
+}
+
+return $o;
+}
diff --git a/include/salmon.php b/include/salmon.php
index b5c21a87b..d7060b0f7 100644
--- a/include/salmon.php
+++ b/include/salmon.php
@@ -161,7 +161,7 @@ EOT;
$signature2 = base64url_encode($rsa->sign($data));
- $salmon_tpl = load_view_file('view/magicsig.tpl');
+ $salmon_tpl = get_markup_template('magicsig.tpl');
$salmon = replace_macros($salmon_tpl,array(
'$data' => $data,
'$encoding' => $encoding,
diff --git a/include/security.php b/include/security.php
index 5e79e1edd..c74a9b4a3 100644
--- a/include/security.php
+++ b/include/security.php
@@ -25,7 +25,7 @@ function can_write_wall(&$a,$owner) {
else {
$r = q("SELECT `contact`.*, `user`.`page-flags` FROM `contact` LEFT JOIN `user` on `user`.`uid` = `contact`.`uid`
WHERE `contact`.`uid` = %d AND `contact`.`id` = %d AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
- AND `readonly` = 0 AND ( `contact`.`rel` IN ( %d , %d ) OR `user`.`page-flags` = %d ) LIMIT 1",
+ AND `user`.`blockwall` = 0 AND `readonly` = 0 AND ( `contact`.`rel` IN ( %d , %d ) OR `user`.`page-flags` = %d ) LIMIT 1",
intval($owner),
intval(remote_user()),
intval(REL_VIP),
diff --git a/include/template_processor.php b/include/template_processor.php
new file mode 100644
index 000000000..efdfbaecb
--- /dev/null
+++ b/include/template_processor.php
@@ -0,0 +1,137 @@
+<?php
+
+ class Template {
+ var $r;
+ var $search;
+ var $replace;
+ var $stack = array();
+ var $nodes = array();
+ var $done = false;
+
+ private function _build_replace($r, $prefix){
+
+ if(is_array($r) && count($r)) {
+ foreach ($r as $k => $v ) {
+ if (is_array($v))
+ $this->_build_replace($v, "$prefix$k.");
+
+ $this->search[] = $prefix . $k;
+ $this->replace[] = $v;
+ }
+ }
+ }
+
+ private function _push_stack(){
+ $this->stack[] = array($this->r, $this->search, $this->replace, $this->nodes);
+ }
+ private function _pop_stack(){
+ list($this->r, $this->search, $this->replace, $this->nodes) = array_pop($this->stack);
+ }
+
+ private function _get_var($name){
+ $keys = array_map('trim',explode(".",$name));
+ $val = $this->r;
+ foreach($keys as $k) {
+ $val = $val[$k];
+ }
+ return $val;
+ }
+
+ /**
+ * IF node
+ *
+ * {{ if <$var> }}...{{ endif }}
+ */
+ private function _replcb_if($args){
+ $val = $this->_get_var($args[2]);
+ return ($val?$args[3]:"");
+ }
+
+ /**
+ * FOR node
+ *
+ * {{ for <$var> as $name }}...{{ endfor }}
+ * {{ for <$var> as $key=>$name }}...{{ endfor }}
+ */
+ private function _replcb_for($args){
+ $m = array_map('trim', explode(" as ", $args[2]));
+ list($keyname, $varname) = explode("=>",$m[1]);
+ if (is_null($varname)) { $varname=$keyname; $keyname=""; }
+ if ($m[0]=="" || $varname=="" || is_null($varname)) die("template error: 'for ".$m[0]." as ".$varname."'") ;
+ $vals = $this->r[$m[0]];
+ $ret="";
+ if (!is_array($vals)) return $ret;
+ foreach ($vals as $k=>$v){
+ $this->_push_stack();
+ $r = $this->r;
+ $r[$varname] = $v;
+ if ($keyname!='') $r[$keyname] = $k;
+ $ret .= $this->replace($args[3], $r);
+ $this->_pop_stack();
+ }
+ return $ret;
+ }
+
+ /**
+ * INC node
+ *
+ * {{ inc <templatefile> [with $var1=$var2] }}{{ endinc }}
+ */
+ private function _replcb_inc($args){
+ list($tplfile, $newctx) = array_map('trim', explode("with",$args[2]));
+ $this->_push_stack();
+ $r = $this->r;
+ if (!is_null($newctx)) {
+ list($a,$b) = array_map('trim', explode("=",$newctx));
+ $r[$a] = $this->_get_var($b);
+ }
+ $this->nodes = Array();
+ $tpl = get_markup_template($tplfile);
+ $ret = $this->replace($tpl, $r);
+ $this->_pop_stack();
+ return $ret;
+
+ }
+
+ private function _replcb_node($m) {
+ $node = $this->nodes[$m[1]];
+ if (method_exists($this, "_replcb_".$node[1])){
+ return call_user_func(array($this, "_replcb_".$node[1]), $node);
+ } else {
+ return "";
+ }
+ }
+
+ private function _replcb($m){
+ $this->done = false;
+ $this->nodes[] = (array) $m;
+ return "||". (count($this->nodes)-1) ."||";
+ }
+
+ private function _build_nodes($s){
+ $this->done = false;
+ while (!$this->done){
+ $this->done=true;
+ $s = preg_replace_callback('|{{ *([a-z]*) *([^}]*)}}([^{]*){{ *end\1 *}}|', array($this, "_replcb"), $s);
+ }
+ krsort($this->nodes);
+ return $s;
+ }
+
+ public function replace($s, $r) {
+ $this->r = $r;
+ $this->search = array();
+ $this->replace = array();
+
+ $this->_build_replace($r, "");
+
+ #$s = str_replace(array("\n","\r"),array("§n§","§r§"),$s);
+ $s = $this->_build_nodes($s);
+ $s = preg_replace_callback('/\|\|([0-9]+)\|\|/', array($this, "_replcb_node"), $s);
+ $s = str_replace($this->search,$this->replace, (string) $s);
+
+ return $s;
+ }
+ }
+
+ $t = new Template;