From 3ad52463f633b060bee519e8aa4d6e9453fdc2aa Mon Sep 17 00:00:00 2001
From: Mike Macgirvin <mike@macgirvin.com>
Date: Mon, 20 Sep 2010 19:34:44 -0700
Subject: [PATCH] more robust feed error handling, at the expense of
 performance. Pass profile owner through HTML (yuk) to the ajax updater - as
 browser  pre-fetch totally buggers passing it via the server session.

---
 include/items.php      |  13 +-
 include/main.js        |   7 +-
 include/poller.php     | 298 ++++++++++++++++++++---------------------
 index.php              |   1 +
 mod/network.php        |   4 +-
 mod/profile.php        |  17 ++-
 mod/update_network.php |   4 +-
 mod/update_profile.php |   4 +-
 8 files changed, 181 insertions(+), 167 deletions(-)

diff --git a/include/items.php b/include/items.php
index 8ca0eeb16f..c7738c3ed5 100644
--- a/include/items.php
+++ b/include/items.php
@@ -91,6 +91,7 @@ function get_feed_for(&$a, $dfrn_id, $owner_id, $last_update, $direction = 0) {
 
 	if(! strlen($last_update))
 		$last_update = 'now - 30 days';
+
 	$check_date = datetime_convert('UTC','UTC',$last_update,'Y-m-d H:i:s');
 
 	$r = q("SELECT `item`.*, `item`.`id` AS `item_id`, 
@@ -109,8 +110,9 @@ function get_feed_for(&$a, $dfrn_id, $owner_id, $last_update, $direction = 0) {
 		dbesc($check_date),
 		dbesc($sort)
 	);
-	if(! count($r))
-		killme();
+
+	// Will check further below if this actually returned results.
+	// We will provide an empty feed in any case.
 
 	$items = $r;
 
@@ -135,7 +137,12 @@ function get_feed_for(&$a, $dfrn_id, $owner_id, $last_update, $direction = 0) {
 			'$namdate'      => xmlify(datetime_convert('UTC','UTC',$owner['name-date']   . '+00:00' , ATOM_TIME)) 
 	));
 
-	
+
+	if(! count($items)) {
+		$atom .= '</feed>' . "\r\n";
+		return $atom;
+	}
+
 	foreach($items as $item) {
 
 		// public feeds get html, our own nodes use bbcode
diff --git a/include/main.js b/include/main.js
index 645170b41e..1ddab0dc2c 100644
--- a/include/main.js
+++ b/include/main.js
@@ -37,6 +37,7 @@
 	var msie = false;
 	var stopped = false;
 	var timer = null;
+	var pr = 0;
 
 	$(document).ready(function() {
 		$.ajaxSetup({cache: false});
@@ -64,8 +65,8 @@
 
 	function NavUpdate() {
 
-		if($('#live-network').length) { src = 'network'; liveUpdate(); }
-		if($('#live-profile').length) { src = 'profile'; liveUpdate(); }
+		if($('#live-network').length) { src = 'network'; pr = $('#live-network').attr('profile'); liveUpdate(); }
+		if($('#live-profile').length) { src = 'profile'; pr = $('#live-profile').attr('profile'); liveUpdate(); }
 
 		if(! stopped) {
 			$.get("ping",function(data) {
@@ -97,7 +98,7 @@
 		}
 		prev = 'live-' + src;
 
-		$.get('update_' + src + '?msie=' + ((msie) ? 1 : 0),function(data) {
+		$.get('update_' + src + '?p=' + pr + '&msie=' + ((msie) ? 1 : 0),function(data) {
 			$('.wall-item-outside-wrapper',data).each(function() {
 				var ident = $(this).attr('id');
 				if($('#' + ident).length == 0) { 
diff --git a/include/poller.php b/include/poller.php
index 0980ca1fa5..e0c721f60f 100644
--- a/include/poller.php
+++ b/include/poller.php
@@ -61,7 +61,6 @@
 				continue;
 		}
 
-
 		$importer_uid = $contact['uid'];
 
 		$r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1",
@@ -96,15 +95,21 @@
 			echo "XML: " . $xml . "\r\n";
 		}
 
-		if(! $xml)
+		if(! $xml) {
+			// dead connection - might be a transient event, or this might
+			// mean the software was uninstalled or the domain expired. 
+			// Will keep trying for one month.
+			mark_for_death($contact);
 			continue;
-
+		}
 
 
 		$res = simplexml_load_string($xml);
 
-		if(intval($res->status) == 1)
+		if(intval($res->status) == 1) {
+			// we may not be friends anymore. Will keep trying for one month.
 			mark_for_death($contact);
+		}
 		else {
 			if($contact['term-date'] != '0000-00-00 00:00:00')
 				unmark_for_death($contact);
@@ -113,7 +118,6 @@
 		if((intval($res->status) != 0) || (! strlen($res->challenge)) || (! strlen($res->dfrn_id)))
 			continue;
 
-
 		$postvars = array();
 
 		$sent_dfrn_id = hex2bin($res->dfrn_id);
@@ -145,7 +149,6 @@
 		$postvars['dfrn_id'] = $idtosend;
 
 
-
 		$xml = post_url($contact['poll'],$postvars);
 
 		if($debugging) {
@@ -153,14 +156,8 @@
 			echo "Length:" . strlen($xml) . "\r\n";
 		}
 
-		if(! strlen($xml)) {
-			// an empty response may mean there's nothing new - record the fact that we checked
-			$r = q("UPDATE `contact` SET `last-update` = '%s' WHERE `id` = %d LIMIT 1",
-				dbesc(datetime_convert()),
-				intval($contact['id'])
-			);
+		if(! strlen($xml))
 			continue;
-		}
 
 		$feed = new SimplePie();
 		$feed->set_raw_data($xml);
@@ -240,157 +237,156 @@
 		}
 
 		// Now process the feed
-		
-		foreach($feed->get_items() as $item) {
+		if($feed->get_item_quantity()) {		
+			foreach($feed->get_items() as $item) {
 
-			$deleted = false;
+				$deleted = false;
 
-			$rawdelete = $item->get_item_tags( NAMESPACE_TOMB, 'deleted-entry');
-			if(isset($rawdelete[0]['attribs']['']['ref'])) {
-				$uri = $rawthread[0]['attribs']['']['ref'];
-				$deleted = true;
-				if(isset($rawdelete[0]['attribs']['']['when'])) {
-					$when = $rawthread[0]['attribs']['']['when'];
-					$when = datetime_convert('UTC','UTC', $when, 'Y-m-d H:i:s');
-				}
-				else
-					$when = datetime_convert('UTC','UTC','now','Y-m-d H:i:s');
-			}
-			if($deleted) {
-				$r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
-					dbesc($uri),
-					intval($importer['uid'])
-				);
-				if(count($r)) {
-					$item = $r[0];
-					if($item['uri'] == $item['parent-uri']) {
-						$r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',
-							`body` = '', `title` = ''
-							WHERE `parent-uri` = '%s' AND `uid` = %d",
-							dbesc($when),
-							dbesc(datetime_convert()),
-							dbesc($item['uri']),
-							intval($importer['uid'])
-						);
+				$rawdelete = $item->get_item_tags( NAMESPACE_TOMB, 'deleted-entry');
+				if(isset($rawdelete[0]['attribs']['']['ref'])) {
+					$uri = $rawthread[0]['attribs']['']['ref'];
+					$deleted = true;
+					if(isset($rawdelete[0]['attribs']['']['when'])) {
+						$when = $rawthread[0]['attribs']['']['when'];
+						$when = datetime_convert('UTC','UTC', $when, 'Y-m-d H:i:s');
 					}
-					else {
-						$r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',
-							`body` = '', `title` = '' 
-							WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
-							dbesc($when),
-							dbesc(datetime_convert()),
-							dbesc($uri),
-							intval($importer['uid'])
-						);
-						if($item['last-child']) {
-							// ensure that last-child is set in case the comment that had it just got wiped.
-							$q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d ",
+					else
+						$when = datetime_convert('UTC','UTC','now','Y-m-d H:i:s');
+				}
+				if($deleted) {
+					$r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
+						dbesc($uri),
+						intval($importer['uid'])
+					);
+					if(count($r)) {
+						$item = $r[0];
+						if($item['uri'] == $item['parent-uri']) {
+							$r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',
+								`body` = '', `title` = ''
+								WHERE `parent-uri` = '%s' AND `uid` = %d",
+								dbesc($when),
 								dbesc(datetime_convert()),
-								dbesc($item['parent-uri']),
-								intval($item['uid'])
+								dbesc($item['uri']),
+								intval($importer['uid'])
 							);
-							// who is the last child now? 
-							$r = q("SELECT `id` FROM `item` WHERE `parent-uri` = '%s' AND `type` != 'activity' AND `deleted` = 0 AND `uid` = %d 
-								ORDER BY `edited` DESC LIMIT 1",
+						}
+						else {
+							$r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',
+								`body` = '', `title` = '' 
+								WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
+								dbesc($when),
+								dbesc(datetime_convert()),
+								dbesc($uri),
+								intval($importer['uid'])
+							);
+							if($item['last-child']) {
+								// ensure that last-child is set in case the comment that had it just got wiped.
+								$q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d ",
+									dbesc(datetime_convert()),
 									dbesc($item['parent-uri']),
-									intval($importer['uid'])
-							);
-							if(count($r)) {
-								q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d LIMIT 1",
-									intval($r[0]['id'])
+									intval($item['uid'])
 								);
-							}
-						}	
-					}
-				}	
-				continue;
-			}
-
-
-			$is_reply = false;		
-			$item_id = $item->get_id();
-			$rawthread = $item->get_item_tags( NAMESPACE_THREAD,'in-reply-to');
-			if(isset($rawthread[0]['attribs']['']['ref'])) {
-				$is_reply = true;
-				$parent_uri = $rawthread[0]['attribs']['']['ref'];
-			}
-
-
-			if($is_reply) {
-
-				// Have we seen it? If not, import it.
-
-				$item_id = $item->get_id();
-
-				$r = q("SELECT `uid`, `last-child`, `edited` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
-					dbesc($item_id),
-					intval($importer['uid'])
-				);
-				// FIXME update content if 'updated' changes
-				if(count($r)) {
-					$allow = $item->get_item_tags( NAMESPACE_DFRN, 'comment-allow');
-					if($allow && $allow[0]['data'] != $r[0]['last-child']) {
-						$r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d",
-							dbesc(datetime_convert()),
-							dbesc($parent_uri),
-							intval($importer['uid'])
-						);
-						$r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s'  WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
-							intval($allow[0]['data']),
-							dbesc(datetime_convert()),
-							dbesc($item_id),
-							intval($importer['uid'])
-						);
-
-
-					}
-					continue;
-				}
-				$datarray = get_atom_elements($item);
-				$datarray['parent-uri'] = $parent_uri;
-				$datarray['uid'] = $importer['uid'];
-				$datarray['contact-id'] = $contact['id'];
-				if(($datarray['verb'] == ACTIVITY_LIKE) || ($datarray['verb'] == ACTIVITY_DISLIKE)) {
-					$datarray['type'] = 'activity';
-					$datarray['gravity'] = GRAVITY_LIKE;
-				}
-
-				$r = item_store($datarray);
-				continue;
-			}
-
-			else {
-				// Head post of a conversation. Have we seen it? If not, import it.
-
-				$item_id = $item->get_id();
-				$r = q("SELECT `uid`, `last-child`, `edited` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
-					dbesc($item_id),
-					intval($importer['uid'])
-				);
-				if(count($r)) {
-					$allow = $item->get_item_tags( NAMESPACE_DFRN, 'comment-allow');
-					if($allow && $allow[0]['data'] != $r[0]['last-child']) {
-						$r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
-							intval($allow[0]['data']),
-							dbesc(datetime_convert()),
-							dbesc($item_id),
-							intval($importer['uid'])
-						);
-					}
+								// who is the last child now? 
+								$r = q("SELECT `id` FROM `item` WHERE `parent-uri` = '%s' AND `type` != 'activity' AND `deleted` = 0 AND `uid` = %d 
+									ORDER BY `edited` DESC LIMIT 1",
+										dbesc($item['parent-uri']),
+										intval($importer['uid'])
+								);
+								if(count($r)) {
+									q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d LIMIT 1",
+										intval($r[0]['id'])
+									);
+								}
+							}	
+						}
+					}	
 					continue;
 				}
 
-				$datarray = get_atom_elements($item);
-				$datarray['parent-uri'] = $item_id;
-				$datarray['uid'] = $importer['uid'];
-				$datarray['contact-id'] = $contact['id'];
-				$r = item_store($datarray);
-				continue;
 
+				$is_reply = false;		
+				$item_id = $item->get_id();
+				$rawthread = $item->get_item_tags( NAMESPACE_THREAD,'in-reply-to');
+				if(isset($rawthread[0]['attribs']['']['ref'])) {
+					$is_reply = true;
+					$parent_uri = $rawthread[0]['attribs']['']['ref'];
+				}
+
+
+				if($is_reply) {
+	
+					// Have we seen it? If not, import it.
+	
+					$item_id = $item->get_id();
+	
+					$r = q("SELECT `uid`, `last-child`, `edited` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
+						dbesc($item_id),
+						intval($importer['uid'])
+					);
+					// FIXME update content if 'updated' changes
+					if(count($r)) {
+						$allow = $item->get_item_tags( NAMESPACE_DFRN, 'comment-allow');
+						if($allow && $allow[0]['data'] != $r[0]['last-child']) {
+							$r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d",
+								dbesc(datetime_convert()),
+								dbesc($parent_uri),
+								intval($importer['uid'])
+							);
+							$r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s'  WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
+								intval($allow[0]['data']),
+								dbesc(datetime_convert()),
+								dbesc($item_id),
+								intval($importer['uid'])
+							);
+
+
+						}
+						continue;
+					}
+					$datarray = get_atom_elements($item);
+					$datarray['parent-uri'] = $parent_uri;
+					$datarray['uid'] = $importer['uid'];
+					$datarray['contact-id'] = $contact['id'];
+					if(($datarray['verb'] == ACTIVITY_LIKE) || ($datarray['verb'] == ACTIVITY_DISLIKE)) {
+						$datarray['type'] = 'activity';
+						$datarray['gravity'] = GRAVITY_LIKE;
+					}
+	
+					$r = item_store($datarray);
+					continue;
+				}
+
+				else {
+					// Head post of a conversation. Have we seen it? If not, import it.
+	
+					$item_id = $item->get_id();
+					$r = q("SELECT `uid`, `last-child`, `edited` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
+						dbesc($item_id),
+						intval($importer['uid'])
+					);
+					if(count($r)) {
+						$allow = $item->get_item_tags( NAMESPACE_DFRN, 'comment-allow');
+						if($allow && $allow[0]['data'] != $r[0]['last-child']) {
+							$r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
+								intval($allow[0]['data']),
+								dbesc(datetime_convert()),
+								dbesc($item_id),
+								intval($importer['uid'])
+							);
+						}
+						continue;
+					}
+
+					$datarray = get_atom_elements($item);
+					$datarray['parent-uri'] = $item_id;
+					$datarray['uid'] = $importer['uid'];
+					$datarray['contact-id'] = $contact['id'];
+					$r = item_store($datarray);
+					continue;
+	
+				}
 			}
-
 		}
-
 		$r = q("UPDATE `contact` SET `last-update` = '%s' WHERE `id` = %d LIMIT 1",
 			dbesc(datetime_convert()),
 			intval($contact['id'])
diff --git a/index.php b/index.php
index 9b9e708f75..0de0afd48d 100644
--- a/index.php
+++ b/index.php
@@ -89,6 +89,7 @@ $a->page['content'] .= $debug_text;
 $a->page['content'] .= '<div id="pause"><img src="" alt="" /></div>';
 // build page
 
+
 // Navigation (menu) template
 if($a->module != 'install')
 	require_once("nav.php");
diff --git a/mod/network.php b/mod/network.php
index c5845f63c8..e9e730340b 100644
--- a/mod/network.php
+++ b/mod/network.php
@@ -7,7 +7,7 @@ function network_init(&$a) {
 }
 
 
-function network_content(&$a, $update = false) {
+function network_content(&$a, $update = 0) {
 
 	if(! local_user())
 		return;
@@ -59,7 +59,7 @@ function network_content(&$a, $update = false) {
 		// criteria is discovered in javascript).
 
 		if($a->pager['start'] == 0 && $a->argc == 1)
-			$o .= '<div id="live-network"></div>' . "\r\n";
+			$o .= '<div id="live-network" profile="' . $_SESSION['uid'] . '"></div>' . "\r\n";
 	}
 
 	// We aren't going to try and figure out at the item, group, and page level 
diff --git a/mod/profile.php b/mod/profile.php
index 31b634013c..0d9c94eedc 100644
--- a/mod/profile.php
+++ b/mod/profile.php
@@ -74,7 +74,11 @@ function profile_init(&$a) {
 }
 
 
-function profile_content(&$a, $update = false) {
+function profile_content(&$a, $update = 0) {
+
+
+	file_put_contents('uid.log',"{$_SERVER['QUERY_STRING']} ". session_id() . "\n", FILE_APPEND);
+
 
 	require_once("include/bbcode.php");
 	require_once('include/security.php');
@@ -86,13 +90,11 @@ function profile_content(&$a, $update = false) {
 
 	if($update) {
 		// Ensure we've got a profile owner if updating.
-		$a->profile['profile_uid'] = $_SESSION['profile_uid'];
+		$a->profile['profile_uid'] = $update;
 	}
 	else {
-		if($a->profile['uid'] == get_uid())		
+		if($a->profile['profile_uid'] == get_uid())		
 			$o .= '<script>	$(document).ready(function() { $(\'#nav-home-link\').addClass(\'nav-selected\'); });</script>';
-		// set the uid so we can pick it up during update
-		$_SESSION['profile_uid'] = $a->profile['uid'];
 	}
 
 	$contact = null;
@@ -158,8 +160,11 @@ function profile_content(&$a, $update = false) {
 			));
 		}
 
+		// This is ugly, but we can't pass the profile_uid through the session to the ajax updater,
+		// because browser prefetching might change it on us. We have to deliver it with the page.
+
 		if($tab == 'posts' && (! $a->pager['start']))
-			$o .= '<div id="live-profile"></div>' . "\r\n";
+			$o .= '<div id="live-profile" profile="' . $a->profile['profile_uid'] . '"></div>' . "\r\n";
 	}
 
 	// TODO alter registration and settings and profile to update contact table when names and  photos change.  
diff --git a/mod/update_network.php b/mod/update_network.php
index 1c790ead16..35e968dba9 100644
--- a/mod/update_network.php
+++ b/mod/update_network.php
@@ -7,12 +7,14 @@ require_once('mod/network.php');
 
 function update_network_content(&$a) {
 
+	$profile_uid = intval($_GET['p']);
+
 	header("Content-type: text/html");
 	echo "<!DOCTYPE html><html><body>\r\n";
 	echo (($_GET['msie'] == 1) ? '<div>' : '<section>');
 
 
-        $text = network_content($a,true);
+        $text = network_content($a,$profile_uid);
         $pattern = "/<img([^>]*) src=\"([^\"]*)\"/";
         $replace = "<img\${1} dst=\"\${2}\"";
         $text = preg_replace($pattern, $replace, $text);
diff --git a/mod/update_profile.php b/mod/update_profile.php
index e5085f6ec0..9a6729396f 100644
--- a/mod/update_profile.php
+++ b/mod/update_profile.php
@@ -7,6 +7,8 @@ require_once('mod/profile.php');
 
 function update_profile_content(&$a) {
 
+	$profile_uid = intval($_GET['p']);
+
 	header("Content-type: text/html");
 	echo "<!DOCTYPE html><html><body>\r\n";
 	echo (($_GET['msie'] == 1) ? '<div>' : '<section>');
@@ -16,7 +18,7 @@ function update_profile_content(&$a) {
         // The only ones we need to fetch are those for new page additions, which we'll discover
         // on the client side and then swap the image back.
 
-        $text = profile_content($a,true);
+        $text = profile_content($a,$profile_uid);
         $pattern = "/<img([^>]*) src=\"([^\"]*)\"/";
         $replace = "<img\${1} dst=\"\${2}\"";
         $text = preg_replace($pattern, $replace, $text);