	synchronized public void fetchUpdatesCaller( String friend, File galleryDir) throws DB461Exception {
		SNetDB461 db = null;
		try {
			db = new SNetDB461(mDBName);
			DDNSRRecord.ARecord ddnsResult;
			JSONObject args;
			Log.i(TAG, "Call to fetchUpdatesCaller for friend "+friend);
			ddnsResult = ddnsResolverService.resolve(friend);
			Log.v(TAG, "Resolved friend "+friend+" to DDNS address "+ddnsResult);
			Log.d(TAG, "Putting together JSON glob");
			JSONObject community = new JSONObject();
			JSONArray needphotos = new JSONArray();
			RecordSet<CommunityRecord> communityRecords = db.COMMUNITYTABLE.readAll();
			for (CommunityRecord cRecord : communityRecords) {
				JSONObject value = new JSONObject()
						.put("generation", cRecord.generation)
						.put("myphotohash", cRecord.myPhotoHash)
						.put("chosenphotohash", cRecord.chosenPhotoHash);
				community.put(cRecord.name.toString(), value);
				if (cRecord.isFriend) {
					PhotoRecord pRecord;
					int photoHash;
					pRecord = db.PHOTOTABLE.readOne(cRecord.myPhotoHash);
					photoHash = cRecord.myPhotoHash;
					if (pRecord == null && photoHash != 0) {
						needphotos.put(photoHash);
					}
					pRecord = db.PHOTOTABLE.readOne(cRecord.chosenPhotoHash);
					photoHash = cRecord.chosenPhotoHash;
					if (pRecord == null && photoHash != 0) {
						needphotos.put(photoHash);
					}
				}
			}
			args = new JSONObject()
				.put("community", community)
				.put("needphotos", needphotos);
			Log.d(TAG, "sending fetchUpdates RPC call with args: "+args);
			JSONObject response = RPCCall.invoke(ddnsResult.ip(), ddnsResult.port(), "snet", "fetchUpdates", args);
			Log.d(TAG, "response JSON of "+response);
			Iterator<String> keysIter;
			JSONObject communityUpdates = response.getJSONObject("communityupdates");
			keysIter = communityUpdates.keys();
			while (keysIter.hasNext()) {
				String name = keysIter.next();
				CommunityRecord cRecord = db.COMMUNITYTABLE.readOne(name);
				if (cRecord == null) {
					Log.i(TAG, "creating new db record for "+name);
					cRecord = db.COMMUNITYTABLE.createRecord();
					cRecord.name = new DDNSFullName(name);
					cRecord.isFriend = false;
				}
				JSONObject recordUpdate = communityUpdates.getJSONObject(name);		
				int genNum = recordUpdate.getInt("generation");
				if (cRecord.generation <= genNum && isValidGenNum(genNum)) {
					Log.v(TAG, "old record for "+name+" was "+cRecord);
					Log.d(TAG, "updating record for "+name+" to "+recordUpdate);
					cRecord.generation = genNum;
					int oldHash = cRecord.myPhotoHash;
					int newHash = recordUpdate.getInt("myphotohash");
					if (oldHash != newHash) {
						incrementPhotoDB(db, newHash, (galleryDir+newHash+".jpg"));
						decrementPhotoDB(db, oldHash);
						cRecord.myPhotoHash = newHash;
					}
					oldHash = cRecord.chosenPhotoHash;
					newHash = recordUpdate.getInt("chosenphotohash");
					if (oldHash != newHash) {
						incrementPhotoDB(db, newHash, (galleryDir+newHash+".jpg"));
						decrementPhotoDB(db, oldHash);
						cRecord.chosenPhotoHash = newHash;
					}
				} else {
					Log.i(TAG, "fetchUpdates returned record for "+name+", but was not more recent than ours");
				}
				db.COMMUNITYTABLE.write(cRecord);
			}
			JSONArray photoHashes = response.getJSONArray("photoupdates");
			for (int i=0; i<photoHashes.length(); i++) {
				int photoHash = photoHashes.getInt(i);
				PhotoRecord pRecord = db.PHOTOTABLE.readOne(photoHash);
				if (pRecord != null) {
					fetchPhotoAndSave(ddnsResult.ip(), ddnsResult.port(), pRecord);
				} else {
					Log.w(TAG, "Photo can't be updated because no Photo DB entry for its hash: "+photoHash);
				}
			}
		} catch(DDNSException e) {
			e.printStackTrace();
		} catch(JSONException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if ( db != null ) db.discard();
		}
	}

	synchronized public void fetchUpdatesCaller( String friend, File galleryDir) throws DB461Exception {
		SNetDB461 db = null;
		try {
			db = new SNetDB461(mDBName);
			DDNSRRecord.ARecord ddnsResult;
			JSONObject args;
			Log.i(TAG, "Call to fetchUpdatesCaller for friend "+friend);
			ddnsResult = ddnsResolverService.resolve(friend);
			Log.v(TAG, "Resolved friend "+friend+" to DDNS address "+ddnsResult);
			Log.d(TAG, "Putting together JSON glob");
			JSONObject community = new JSONObject();
			JSONArray needphotos = new JSONArray();
			RecordSet<CommunityRecord> communityRecords = db.COMMUNITYTABLE.readAll();
			for (CommunityRecord cRecord : communityRecords) {
				JSONObject value = new JSONObject()
						.put("generation", cRecord.generation)
						.put("myphotohash", cRecord.myPhotoHash)
						.put("chosenphotohash", cRecord.chosenPhotoHash);
				community.put(cRecord.name.toString(), value);
				if (cRecord.isFriend) {
					PhotoRecord pRecord;
					int photoHash;
					pRecord = db.PHOTOTABLE.readOne(cRecord.myPhotoHash);
					photoHash = cRecord.myPhotoHash;
					if (pRecord == null && photoHash != 0) {
						needphotos.put(photoHash);
					}
					pRecord = db.PHOTOTABLE.readOne(cRecord.chosenPhotoHash);
					photoHash = cRecord.chosenPhotoHash;
					if (pRecord == null && photoHash != 0) {
						needphotos.put(photoHash);
					}
				}
			}
			args = new JSONObject()
				.put("community", community)
				.put("needphotos", needphotos);
			Log.d(TAG, "sending fetchUpdates RPC call with args: "+args);
			JSONObject response = RPCCall.invoke(ddnsResult.ip(), ddnsResult.port(), "snet", "fetchUpdates", args);
			Log.d(TAG, "response JSON of "+response);
			Iterator<String> keysIter;
			JSONObject communityUpdates = response.getJSONObject("communityupdates");
			keysIter = communityUpdates.keys();
			while (keysIter.hasNext()) {
				String name = keysIter.next();
				CommunityRecord cRecord = db.COMMUNITYTABLE.readOne(name);
				if (cRecord == null) {
					Log.i(TAG, "creating new db record for "+name);
					cRecord = db.COMMUNITYTABLE.createRecord();
					cRecord.name = new DDNSFullName(name);
					cRecord.isFriend = false;
				}
				JSONObject recordUpdate = communityUpdates.getJSONObject(name);		
				int genNum = recordUpdate.getInt("generation");
				if (cRecord.generation <= genNum && isValidGenNum(genNum)) {
					Log.v(TAG, "old record for "+name+" was "+cRecord);
					Log.d(TAG, "updating record for "+name+" to "+recordUpdate);
					cRecord.generation = genNum;
					int oldHash = cRecord.myPhotoHash;
					int newHash = recordUpdate.getInt("myphotohash");
					if (oldHash != newHash) {
						incrementPhotoDB(db, newHash, (galleryDir.getCanonicalPath()+ File.separatorChar+newHash+".jpg"));
						decrementPhotoDB(db, oldHash);
						cRecord.myPhotoHash = newHash;
					}
					oldHash = cRecord.chosenPhotoHash;
					newHash = recordUpdate.getInt("chosenphotohash");
					if (oldHash != newHash) {
						incrementPhotoDB(db, newHash, (galleryDir.getCanonicalPath()+ File.separatorChar+newHash+".jpg"));
						decrementPhotoDB(db, oldHash);
						cRecord.chosenPhotoHash = newHash;
					}
				} else {
					Log.i(TAG, "fetchUpdates returned record for "+name+", but was not more recent than ours");
				}
				db.COMMUNITYTABLE.write(cRecord);
			}
			JSONArray photoHashes = response.getJSONArray("photoupdates");
			for (int i=0; i<photoHashes.length(); i++) {
				int photoHash = photoHashes.getInt(i);
				PhotoRecord pRecord = db.PHOTOTABLE.readOne(photoHash);
				if (pRecord != null) {
					fetchPhotoAndSave(ddnsResult.ip(), ddnsResult.port(), pRecord);
				} else {
					Log.w(TAG, "Photo can't be updated because no Photo DB entry for its hash: "+photoHash);
				}
			}
		} catch(DDNSException e) {
			e.printStackTrace();
		} catch(JSONException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if ( db != null ) db.discard();
		}
	}
