Monday, November 08, 2010 at 12:04 AM.


on server (dbname, ipaddress, lastupdate, username, mailaddress, serialnumber) {
	<<Return new and changed parts of a database since the last update.
			<<12/7/03; 11:52:32 PM by JES
				<<Add callback support. Callbacks are in config.mainResponder.callbacks.subscriptionsServer. They take the same parameters as this RPC handler. If any callback returns false, then an error is generated.
			<<11/04/00; 5:55:40 PM by PBS
				<<Return the time on the server of the last update, so clients don't miss updates.
	bundle { //add a record to the subscription log
		local (adrtable = log.addToGuestDatabase ("subscriptions"));
		adrtable^.dbname = dbname;
		adrtable^.ipaddress = ipaddress;
		adrtable^.lastupdate = lastupdate;
		adrtable^.username = username;
		adrtable^.mailaddress = mailaddress;
		adrtable^.serialnumber = serialnumber};
	bundle { //call callbacks
		local (adrcallbacks = @config.mainResponder.callbacks.subscriptionsServer);
		if not defined (adrcallbacks^) {
			new (tableType, adrcallbacks)};
		local (adr, ct = sizeOf (adrcallbacks^), i, flSendUpdate = true);
		for i = 1 to ct {
			adr = @adrcallbacks^[i];
			try {
				while typeOf (adr^) == addressType {
					adr = adr^};
				if not adr^ (dbname, ipaddress, lastupdate, username, mailaddress, serialnumber) {
					flSendUpdate = false}};
			if not flSendUpdate {
				scriptError ("Can't update because you are not authorized for updates to this database.")}}};
	local (adrdb = @user.databases.[dbname]);
	if not defined (adrdb^) {
		scriptError ("Can't send you an update because the sysop hasn't registered a database named \"" + dbname + "\".")};
	if not (adrdb^.supportsSubscribe) {
		scriptError ("Can't send you an update because the database \"" + dbname + "\" doesn't support subscriptions.")};
	local (adrguestdatabase = @[adrdb^.f]);
	table.sureDatabaseOpen (adrguestdatabase);
	lastupdate = date (lastupdate); //convert from a net-standard-string
	local (frontierVersion = Frontier.version ());
	local (adrchanges = @adrguestdatabase^.["#changes"]);
	local (sizechanges = sizeof (adrchanges^));
	local (parts);
	new (tabletype, @parts);
	parts.serialNum = sizechanges; //it's synthetic!
	parts.lastUpdateTime = date.netStandardString ( ()); //PBS 11/4/00: save server time on client, to avoid missing updates
	new (tabletype,;
	local (i, addeditems = {});
	for i = sizechanges downto 1 {
		local (adritem = @adrchanges^ [i]);
		if adritem^.when < lastupdate {
		if addeditems contains adritem^.what { //we've already included this
		local (name = "part" + string.padwithzeros (i, 4));
		local (adrnewpart =[name]);
		new (tabletype, adrnewpart);
		bundle { //2/14/99; 9:01:26 AM by DW, customized error if object doesn't exist
			if not defined (adritem^.what^) {
				scriptError ("Can't do the update because the #changes table in \"" + dbname + "\" on the server says that \"" + adritem^.what + "\" has changed, but the object isn't in the database.")};
			adrnewpart^.data = adritem^.what^};
		adrnewpart^.timestamp = adritem^.when;
		adrnewpart^.userName = adritem^.who;
		bundle { //put the relative address into adr field
			local (s = string (adritem^.what));
			local (ix = string.patternMatch ("].", s));
			s = string.delete (s, 1, ix + 1);
			adrnewpart^.adr = s};
		wp.newtextobject ("", @adrnewpart^.changes);
		adrnewpart^.platform = "both";
		adrnewpart^.version = frontierVersion;
		local (bytes);
		pack (adrnewpart^, @bytes);
		bytes = base64.encode (bytes, infinity);
		delete (adrnewpart);
		adrnewpart^ = bytes;
		addeditems = addeditems + {adritem^.what};
		sys.systemTask ()};
	return (parts)}
<<bundle //test code
	<<server ("prefs.root", tcp.dns.getMyDottedId (), (), "Jake", "", 10)

This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.