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

system.verbs.builtins.mainResponder.adminSite.macros.manageSite

on manageSite (adrinfo) {
	<<Changes
		<<12/13/03; 12:28:34 AM by JES
			<<If the discussion group doesn't specify a message reader URL, first check the site's #urls table, and if not found there, generate one.
		<<9/8/02; 5:05:08 PM by JES
			<<Added a command to toggle search indexing of discussion group messages.
		<<9/3/02; 4:13:16 AM by JES
			<<Added an access permission display to the Basic information section -- public or private (editors-only), with a command to toggle the public/private status of the site.
		<<8/29/02; 8:42:35 PM by JES
			<<Make a backup of deleted sites before deleting them.
		<<8/29/02; 3:51:49 PM by JES
			<<Added the ability to delete sites from the server. Added search engine de-indexing when a site is disabled or deleted.
		<<6/9/02; 3:54:37 PM by JES
			<<Created. Present a UI for managing a Manila site.
	local (pta = html.getPageTableAddress ());
	pta^.title = "Manage site: " + adrinfo^.displaySiteName;
	local (thisPageUrl = "http://" + pta^.host + "/?" + pta^.searchArgs);
	local (bgcolor1 = pta^.trbg1, bgcolor2 = pta^.trbg2, ctitems);
	local (adrsite = adrinfo^.adrsite);
	local (adrnewssite = manilaSuite.getNewsSiteAddress (adrsite));
	local (adrdg = adrinfo^.adrDiscuss);
	local (adrmsgs = @adrdg^.messages);
	local (msgReaderUrl);
	bundle { //set msgReaderUrl
		if defined (adrdg^.prefs.msgReaderUrl) {
			msgReaderUrl = adrdg^.prefs.msgReaderUrl}
		else {
			if defined (adrsite^.["#urls"].discussMsgReader) {
				msgReaderUrl = adrsite^.["#urls"].discussMsgReader}
			else {
				msgReaderUrl = adrinfo^.siteUrl + "discuss/msgReader$"}}};
	local (yesterday = date.yesterday (clock.now ()));
	
	local (htmlText = "", indentlevel = 0);
	on add (s) {
		htmlText = htmlText + (string.filledString ("\t", indentlevel) + s + "\r");};
	on addRow (itemname, itemvalue, linktext="", linkurl="") {
		local (widthstring = "");
		if ctitems == 0 {
			widthstring = " width=\"200\""};
		if (ctitems++ % 2) == 0 {
			bgcolor = bgcolor1}
		else {
			bgcolor = bgcolor2};
		add ("<tr bgcolor=\"" + bgcolor + "\">"); indentlevel++;
		add ("<td valign=\"top\" style=\"padding-right: 15px;\"" + widthstring + ">" + itemname + ":</td>");
		add ("<td valign=\"top\">" + itemvalue + "</td>");
		if sizeOf (linktext) > 0 {
			local (link = linktext);
			if sizeOf (linkurl) > 0 {
				link = html.getlink (linktext, linkurl)};
			add ("<td valign=\"top\" align=\"right\">" + link + "  </td>")}
		else {
			add ("<td></td>")};
		add ("</tr>"); indentlevel--};
	on addHeader (s) {
		add ("<h4>" + s + "</h4>");
		add ("<table cellpadding=\"3\" cellspacing=\"0\" border=\"0\" width=\"100%\">"); indentlevel++;
		ctitems = 0}; //reset the bgcolor
	on addFooter () {
		add ("</table>"); indentlevel--};
	on shortDateTime (d) {
		if d < yesterday {
			return (date.shortString (d))}
		else {
			return (string.timeString (d))}};
	
	local (command = "view", message = "");
	if defined (system.temp.mainResponder.misc.message) {
		message = string.replaceAll (system.temp.mainResponder.misc.message, "\"", "\\\"");
		delete (@system.temp.mainResponder.misc.message)};
	if defined (pta^.searchArgTable.command) {
		command = pta^.searchArgTable.command};
	if defined (pta^.postArgs.command) {
		command = pta^.postArgs.command};
	case command { //handle admin commands
		"enable" {
			pta^.title = "Enable site: " + adrinfo^.displaySiteName;
			case pta^.method {
				"GET" {
					add ("<form method=\"POST\">"); indentlevel++;
					add ("<p>To enable this site, enter the URL where it will be served, and click the Enable Site button.</p>");
					add ("<p><br />URL: <input type=\"text\" name=\"siteUrl\" size=\"80\" maxlength=\"255\" value=\"" + adrinfo^.siteurl + "\" /></p>");
					add ("<p><br /><input type=\"submit\" name=\"enableSite\" value=\"Enable Site\" /></p>");
					add ("</form>"); indentlevel--};
				"POST" {
					manilaSuite.installSite (adrsite);
					adrinfo^.flInstalled = true;
					local (newUrl = pta^.postArgs.siteUrl);
					local (oldUrl = adrinfo^.siteurl);
					if not (newUrl endsWith "/") {
						newUrl = newUrl + "/"};
					if not (string.lower (newUrl) beginsWith "http://") {
						newUrl = "http://" + newUrl};
					if string.lower (oldUrl) != string.lower (newUrl) {
						manilaSuite.admin.changeSiteUrl (oldUrl, newUrl, adrsite)};
					adrsite^.["#newsSite"].search.siteUrl = newUrl;
					adrsite^.["#newsSite"].rssInfo.channelLink = newUrl;
					adrsite^.["#newsSite"].rssInfo.imageLink = newUrl;
					adrinfo^.siteUrl = newUrl;
					system.temp.mainResponder.misc.message = "The \"" + adrinfo^.displaySiteName + "\" site has been installed successfully.";
					delete (@pta^.searchArgTable.command);
					local (url = "http://" + pta^.host + "/?" + webserver.encodeArgs (@pta^.searchArgTable));
					mainResponder.redirect (url);
					return ("")}}};
		"disable" {
			pta^.title = "Disable site: " + adrinfo^.displaySiteName;
			case pta^.method {
				"GET" {
					bundle { //disable site
						add ("<form method=\"POST\">"); indentlevel++;
						add ("<p>To disable this site click the Disable Site button below. Disabled sites are listed on the admin site home page, but will not be served by the server. You can enable the site at any time, by clicking the enable link on the Manage site page.</p>");
						add ("<p>To delete this site click the Delete Site button below. Deleted sites are removed completely from the server, and will no longer appear on the admin site home page.</p>");
						if config.mainResponder.prefs.flSearchEngine {
							add ("<p>Any pages in this site which have been indexed by Frontier's search engine will be removed from the index.</p>")};
						add ("<p><br /><input type=\"submit\" name=\"disableSite\" value=\"Disable Site\" />   <input type=\"submit\" name=\"deleteSite\" value=\"Delete Site\" /></p>");
						add ("</form>"); indentlevel--};
					bundle { //delete site
						add ("<form method=\"POST\">"); indentlevel++;
						add ("<p><br /></p>");
						add ("</form>"); indentlevel--}};
				"POST" {
					if defined (pta^.postArgs.deleteSite) { //confirm site deletion
						pta^.title = "Delete site: " + adrinfo^.displaySiteName;
						add ("<form method=\"POST\">"); indentlevel++;
						add ("<p>Are you sure you want to completely delete \"" + adrinfo^.displaySiteName + "\" from the server?</p><p><i>This operation is permanent and cannot be undone.</i></p>");
						add ("<p><br /><br /><input type=\"submit\" name=\"cancelDelete\" value=\"Cancel\" />   <input type=\"submit\" name=\"confirmDelete\" value=\"Delete Site\" /></p>");
						add ("</form>"); indentlevel--}
					else {
						if defined (pta^.postArgs.cancelDelete) { //redirect back to the main page
							delete (@pta^.searchArgTable.command);
							local (url = "http://" + pta^.host + "/?" + webserver.encodeArgs (@pta^.searchArgTable));
							mainResponder.redirect (url);
							return ("")}
						else { //uninstall or confirmed delete
							local (t); new (tableType, @t); //a dummy table for backup info
							manilaSuite.backups.backupOneSite (adrsite, @t);
							manilaSuite.unInstallSite (adrsite);
							if config.mainResponder.prefs.flSearchEngine {
								thread.callScript (@mainResponder.search.server.restartIndex, {adrinfo^.displaySiteName} )};
							adrinfo^.flInstalled = false;
							if defined (pta^.postArgs.confirmDelete) {
								delete (adrsite);
								delete (adrinfo);
								mainResponder.redirect (mainResponder.adminSite.urls.home)}
							else {
								system.temp.mainResponder.misc.message = "The \"" + adrinfo^.displaySiteName + "\" site has been uninstalled.";
								delete (@pta^.searchArgTable.command);
								local (url = "http://" + pta^.host + "/?" + webserver.encodeArgs (@pta^.searchArgTable));
								mainResponder.redirect (url)};
							return ("")}}}}};
		"changeUrl" {
			pta^.title = "Change site URL: " + adrinfo^.displaySiteName;
			case pta^.method {
				"GET" {
					add ("<form method=\"POST\">"); indentlevel++;
					add ("<p>To change this site's URL, enter the URL and click the Change URL button.</p>");
					add ("<p><br />URL: <input type=\"text\" name=\"siteUrl\" size=\"80\" maxlength=\"255\" value=\"" + adrinfo^.siteurl + "\" /></p>");
					add ("<p><br /><input type=\"submit\" name=\"changeUrl\" value=\"Change URL\" /></p>");
					add ("</form>"); indentlevel--};
				"POST" {
					local (newUrl = pta^.postArgs.siteUrl);
					local (oldUrl = adrinfo^.siteurl);
					if not (newUrl endsWith "/") {
						newUrl = newUrl + "/"};
					if not (string.lower (newUrl) beginsWith "http://") {
						newUrl = "http://" + newUrl};
					if string.lower (oldUrl) != string.lower (newUrl) {
						manilaSuite.admin.changeSiteUrl (oldUrl, newUrl, adrsite)};
					adrsite^.["#newsSite"].rssInfo.channelLink = newUrl;
					adrsite^.["#newsSite"].rssInfo.imageLink = newUrl;
					adrsite^.["#newsSite"].search.siteUrl = newUrl;
					adrinfo^.siteUrl = newUrl;
					system.temp.mainResponder.misc.message = "The URL for \"" + adrinfo^.displaySiteName + "\" has been changed successfully.";
					delete (@pta^.searchArgTable.command);
					local (url = "http://" + pta^.host + "/?" + webserver.encodeArgs (@pta^.searchArgTable));
					mainResponder.redirect (url);
					return ("")}}};
		"changeMembershipGroup" {
			pta^.title = "Change Membership Group: " + adrinfo^.displaySiteName;
			case pta^.method {
				"GET" {
					add ("<form method=\"POST\">"); indentlevel++;
					add ("<p>To change this membership group enter the membership group name, and click the Change Group button.</p>");
					add ("<p><br />Membership Group: <input type=\"text\" name=\"membershipGroup\" size=\"80\" maxlength=\"255\" value=\"" + manilaSuite.members.getGroupNameFromSiteAddress (adrsite) + "\" /></p>");
					add ("<p><br /><input type=\"submit\" name=\"changeMembershipGroup\" value=\"Change Group\" /></p>");
					add ("</form>"); indentlevel--};
				"POST" {
					local (groupName = pta^.postArgs.membershipGroup);
					try {
						local (adrgroup = mainResponder.members.getMembershipTable (groupName)); //will error if there's no group with the entered name
						on doTable (adrtable) {
							bundle { //find reasons not to do this table
								if adrtable == adrmsgs { //skip discussion group messasge tables
									return};
								if string.lower (nameOf (adrtable^)) == "#membershipgroup" {
									return}};
							local (adr);
							for adr in adrtable {
								local (lowerItemName = string.lower (nameOf (adr^)));
								case (typeOf (adr^)) {
									tableType {
										doTable (adr)}; //recurse
									stringType {
										case lowerItemName {
											"#members";
											"defaultmembershipgroup";
											"membershipgroup";
											"sysopmemberofgroup" {
												adr^ = groupName}}}}};
							return (true)};
						doTable (adrsite);
						system.temp.mainResponder.misc.message = "The membership group for \"" + adrinfo^.displaySiteName + "\" has been changed successfully."}
					else {
						system.temp.mainResponder.misc.message = "<i>Couldn't change the membership group for \"" + adrinfo^.displaySiteName + "\", because there is no group named \"" + groupName + "\".</i>"};
					delete (@pta^.searchArgTable.command);
					local (url = "http://" + pta^.host + "/?" + webserver.encodeArgs (@pta^.searchArgTable));
					mainResponder.redirect (url);
					return ("")}}};
		"enableBackups" {
			manilaSuite.backups.enableOneSite (adrsite);
			system.temp.mainResponder.misc.message = "Automatic backups of \"" + adrinfo^.displaySiteName + "\" have been enabled.";
			delete (@pta^.searchArgTable.command);
			local (url = "http://" + pta^.host + "/?" + webserver.encodeArgs (@pta^.searchArgTable));
			mainResponder.redirect (url);
			return ("")};
		"disableBackups" {
			manilaSuite.backups.disableOneSite (adrsite);
			system.temp.mainResponder.misc.message = "Automatic backups of \"" + adrinfo^.displaySiteName + "\" have been disabled.";
			delete (@pta^.searchArgTable.command);
			local (url = "http://" + pta^.host + "/?" + webserver.encodeArgs (@pta^.searchArgTable));
			mainResponder.redirect (url);
			return ("")};
		"backupNow" {
			pta^.title = "Backup site: " + adrinfo^.displaySiteName;
			case pta^.method {
				"GET" {
					add ("<form method=\"POST\">"); indentlevel++;
					add ("<p><br />To make an immediate backup of this site click the Backup Site button below. Only new or changed content will be backed up.</p>");
					add ("<p><br /><br /><input type=\"submit\" name=\"backupSite\" value=\"Backup Site\" /></p>");
					add ("</form>"); indentlevel--};
				"POST" {
					local (adrconfig = manilaSuite.backups.initSiteInfo (adrsite));
					local (data); new (tableType, @data);
					manilaSuite.backups.backupOneSite (adrsite, @data);
					adrconfig^.whenLastBackedUp = clock.now ();
					system.temp.mainResponder.misc.message = "\"" + adrinfo^.displaySiteName + "\" has been backed up. " + data.ctfilesbackedup + " of " + data.ctfiles + " files saved, for a total of " + string.megabyteString (data.ctbytesbackedup) + ". " + data.cterrors + " errors.";
					delete (@pta^.searchArgTable.command);
					local (url = "http://" + pta^.host + "/?" + webserver.encodeArgs (@pta^.searchArgTable));
					mainResponder.redirect (url);
					return ("")}}};
		"enableSearch" {
			adrnewssite^.search.flIndex = true;
			system.temp.mainResponder.misc.message = "Search engine indexing of pages in \"" + adrinfo^.displaySiteName + "\" has been enabled.";
			delete (@pta^.searchArgTable.command);
			local (url = "http://" + pta^.host + "/?" + webserver.encodeArgs (@pta^.searchArgTable));
			mainResponder.redirect (url);
			return ("")};
		"disableSearch" {
			adrnewssite^.search.flIndex = false;
			system.temp.mainResponder.misc.message = "Search engine indexing of pages in \"" + adrinfo^.displaySiteName + "\" has been disabled.";
			delete (@pta^.searchArgTable.command);
			local (url = "http://" + pta^.host + "/?" + webserver.encodeArgs (@pta^.searchArgTable));
			mainResponder.redirect (url);
			return ("")};
		"configureSearch" {
			pta^.title = "Configure Search Indexing: " + adrinfo^.displaySiteName;
			add ("<form method=\"POST\">"); indentlevel++;
			add ("<p>Enter information about the search server that will index this site, and click the Submit button.</p>");
			add ("<table cellpadding=\"8\" cellspacing=\"0\" border=\"0\">");
			add (radio.prefs.stringPref ("Server domain name or IP address", @adrnewssite^.search.serverDomain));
			add (radio.prefs.numberPref ("Server port", @adrnewssite^.search.serverPort));
			add (radio.prefs.stringPref ("Server RPC path", @adrnewssite^.search.serverRpcPath));
			add (radio.prefs.stringPref ("Index XML-RPC procedure", @adrnewssite^.search.serverProcedureName));
			add ("</table>");
			add ("<p><br /><input type=\"submit\" name=\"configureSearch\" value=\"Submit\" /></p>");
			add ("</form>"); indentlevel--;
			if pta^.method == "POST" {
				system.temp.mainResponder.misc.message = "The search engine server for \"" + adrinfo^.displaySiteName + "\" has been changed.";
				delete (@pta^.searchArgTable.command);
				local (url = "http://" + pta^.host + "/?" + webserver.encodeArgs (@pta^.searchArgTable));
				mainResponder.redirect (url);
				return ("")}};
		"enableDgIndexing" {
			adrnewssite^.search.flIndexDgMessages = true;
			system.temp.mainResponder.misc.message = "Indexing of discussion group messages for \"" + adrinfo^.displaySiteName + "\" has been enabled.";
			delete (@pta^.searchArgTable.command);
			local (url = "http://" + pta^.host + "/?" + webserver.encodeArgs (@pta^.searchArgTable));
			mainResponder.redirect (url);
			return ("")};
		"disableDgIndexing" {
			adrnewssite^.search.flIndexDgMessages = false;
			system.temp.mainResponder.misc.message = "Indexing of discussion group messages for \"" + adrinfo^.displaySiteName + "\" has been disabled.";
			delete (@pta^.searchArgTable.command);
			local (url = "http://" + pta^.host + "/?" + webserver.encodeArgs (@pta^.searchArgTable));
			mainResponder.redirect (url);
			return ("")};
		"indexSite" {
			pta^.title = "Index entire site: " + adrinfo^.displaySiteName;
			case pta^.method {
				"GET" {
					add ("<form method=\"POST\">"); indentlevel++;
					add ("<p>To index this entire site, click the Index Site button below. Depending on the size of the site, this may take some time, and will slow the server down while indexing is in progress.</p>");
					add ("<p>If you don't want to index the site now, click your browser's Back button.</p>");
					add ("<p><br /><input type=\"submit\" name=\"indexSite\" value=\"Index Site\" /></p>");
					add ("</form>"); indentlevel--};
				"POST" {
					manilaSuite.search.init (adrsite);
					thread.callscript (@manilaSuite.search.threadedSiteIndex, {adrsite});
					system.temp.mainResponder.misc.message = "Search engine indexing of \"" + adrinfo^.displaySiteName + "\" has started. You can monitor indexing status in the Search section below.";
					delete (@pta^.searchArgTable.command);
					local (url = "http://" + pta^.host + "/?" + webserver.encodeArgs (@pta^.searchArgTable));
					mainResponder.redirect (url);
					return ("")}}};
		"deIndexSite" {
			pta^.title = "De-index entire site: " + adrinfo^.displaySiteName;
			case pta^.method {
				"GET" {
					add ("<form method=\"POST\">"); indentlevel++;
					add ("<p>To de-index this entire site, click the De-index Site button below. Depending on the number of indexed pages, this may take some time, and will slow the server down while de-indexing is in progress.</p>");
					add ("<p>If you don't want to de-index the site now, click your browser's Back button.</p>");
					add ("<p><br /><input type=\"submit\" name=\"deIndexSite\" value=\"De-index Site\" /></p>");
					add ("</form>"); indentlevel--};
				"POST" {
					local (adrdata = manilaSuite.search.init (adrsite));
					adrdata^.indexQueue.flRunning = false; //make sure it won't be kicked off again
					local (sitetodeindex = adrinfo^.displaySiteName);
					thread.callScript (@mainResponder.search.server.restartIndex, {sitetodeindex});
					system.temp.mainResponder.misc.message = "Search engine de-indexing of \"" + sitetodeindex + "\" has started. Depending on the number of pages in the index, it may take a few minutes for the operation to complete.";
					delete (@pta^.searchArgTable.command);
					local (url = "http://" + pta^.host + "/?" + webserver.encodeArgs (@pta^.searchArgTable));
					mainResponder.redirect (url);
					return ("")}}};
		"makePrivate" {
			adrnewssite^.flEditorsOnlyAccessToSite = true;
			system.temp.mainResponder.misc.message = "This site has been made private.";
			delete (@pta^.searchArgTable.command);
			local (url = "http://" + pta^.host + "/?" + webserver.encodeArgs (@pta^.searchArgTable));
			mainResponder.redirect (url);
			return ("")};
		"makePublic" {
			adrnewssite^.flEditorsOnlyAccessToSite = false;
			system.temp.mainResponder.misc.message = "This site has been made public.";
			delete (@pta^.searchArgTable.command);
			local (url = "http://" + pta^.host + "/?" + webserver.encodeArgs (@pta^.searchArgTable));
			mainResponder.redirect (url);
			return ("")}}
	else { //display site info
		if sizeOf (message) > 0 { //confirmation message
			add ("<p><b>" + message + "</b></p>")};
		bundle { //basic info
			addHeader ("Basic information");
			bundle { //status -- installed/not installed
				local (s, cmd);
				if adrinfo^.flInstalled {
					s = "This site is enabled.";
					cmd = "disable"}
				else {
					s = "This site is disabled.";
					cmd = "enable"};
				addRow ("Status", s, cmd, thisPageUrl + "&command=" + cmd)};
			addRow ("URL", adrinfo^.siteUrl, "change URL", thisPageUrl + "&command=changeUrl");
			addRow ("Tagline", adrinfo^.tagline);
			bundle { //owner
				local (editor = adrinfo^.managingEditor);
				local (editorlink = editor);
				bundle { //set editorLink
					if adrinfo^.flInstalled {
						editorlink = html.getLink (editor, adrinfo^.profilesUrl + editor);
						try { //get the real name of the editor, if possible
							local (adrmember = @adrinfo^.adrMembers^.[editor]);
							if (defined (adrmember^.personalInfo.name)) and (adrmember^.personalInfo.name != "") {
								editorlink = html.getLink (adrmember^.personalInfo.name, adrinfo^.profilesUrl + editor)}}}
					else {
						editorlink = string.replace (editor, "@", "\\@")}};
				addRow ("Owner", editorlink)};
			bundle { //access
				local (flEditorsOnly = boolean (manilaSuite.getNewsSitePref ("flEditorsOnlyAccessToSite", adrsite, false, true)) );
				if flEditorsOnly {
					addRow ("Access", "Private (editors-only)", "make public", thisPageUrl + "&command=makePublic")}
				else {
					addRow ("Access", "Public", "make private", thisPageUrl + "&command=makePrivate")}};
			addRow ("Created", adrmsgs^[1].postTime);
			addRow ("Last modified", adrinfo^.modified);
			bundle { //database
				local (f, dbname, addresslist = string.parseAddress (adrsite));
				f = addresslist[1];
				if f == "root" {
					f = frontier.getFilePath ()};
				dbname = file.fileFromPath (f);
				addRow ("Database", dbname)};
			bundle { //site adderss
				addRow ("Site address", "@" + string.popFileFromAddress (adrsite))};
			addRow ("Membership group", manilaSuite.members.getGroupNameFromSiteAddress (adrsite), "change", thisPageUrl + "&command=changeMembershipGroup");
			addFooter ()};
		bundle { //backups
			addHeader ("Backups");
			local (canonicalSiteName = adrinfo^.site);
			try {canonicalSiteName = manilaSuite.getCanonicalSiteName (adrsite)};
			local (adrdata = @config.manila.backups.sites.[canonicalSiteName]);
			local (flEnabled = false, whenLastBackup = "never backed up");
			bundle { //set flEnabled and whenLastBackup
				if defined (adrdata^) {
					flEnabled = adrdata^.flEnabled;
					if adrdata^.whenLastBackedUp != date (0) {
						whenLastBackup = adrdata^.whenLastBackedUp}}};
			if flEnabled {
				addRow ("Enabled/disabled", "Automatic backups are enabled for this site", "disable", thisPageUrl + "&command=disableBackups")}
			else {
				addRow ("Enabled/disabled", "Automatic backups are disabled for this site", "enable", thisPageUrl + "&command=enableBackups")};
			addRow ("Last backed up", whenLastBackup, "backup now", thisPageUrl + "&command=backupNow");
			addFooter ()};
		bundle { //contentStats stats (dg, gems)
			addHeader ("Content");
			local (adrstats = @adrinfo^.contentStats);
			if not defined (adrstats^) { //build a table of stats, and store it in the info cache
				local (ctmsgs=0, ctnewsitems=0, ctpostednewsitems=0, ctpics=0, ctstories=0, ctgems=0, gemstotalsizedouble=0.0);
				bundle { //collect info
					ctmsgs = sizeOf (adrmsgs^);
					local (picturesCategory = manilaSuite.discuss.getPicturesCategory (adrSite));
					local (storiesCategory = manilaSuite.discuss.getStoriesCategory (adrSite));
					local (adr);
					for adr in adrmsgs { //count pictures, stories and news items
						if defined (adr^.alsoListedIn) {
							if adr^.alsoListedIn contains picturesCategory {
								ctpics++};
							if adr^.alsoListedIn contains storiesCategory {
								ctstories++}};
						if defined (adr^.newsItem) {
							ctnewsitems++;
							if manilaSuite.news.isPosted (adr) {
								ctpostednewsitems++}}};
					local (adrgems = manilaSuite.gems.getSiteDataAddress (adrSite));
					for adr in adrgems {
						if defined (adr^.flDeleted) { //skip if deleted
							if adr^.flDeleted {
								continue}};
						local (sizeonegem);
						try { //will fail if the file doesn't exist
							sizeonegem = manilaSuite.gems.getFileSize (adr);
							gemstotalsizedouble = gemstotalsizedouble + sizeonegem;
							ctgems++}}};
				bundle { //cache info
					new (tableType, adrstats);
					adrstats^.ctMsgs = ctmsgs;
					adrstats^.ctNewsItems = ctnewsitems;
					adrstats^.ctNewsItemsPosted = ctpostednewsitems;
					adrstats^.ctPictures = ctpics;
					adrstats^.ctStories = ctstories;
					adrstats^.ctGems = ctGems;
					adrstats^.gemsTotalSizeBytes = gemstotalsizedouble}};
			addRow ("Discussion group messages", adrstats^.ctMsgs);
			bundle { //last 5 threads
				local (adrmsg, i, ct = 0, sizeDg = sizeOf (adrmsgs^));
				local (s = "<table cellpadding=\"2\" cellspacing=\"0\" border=\"0\" width=\"95%\">");
				for i = sizeDg downto 1 {
					adrmsg = @adrmsgs^[i];
					if adrmsg^.inResponseTo != 0 {
						continue};
					ct++;
					local (link = mainResponder.discuss.linkToMessage (adrmsg, msgReaderUrl));
					s = s + ("<tr><td valign=\"top\" class=\"small\" width=\"15\">" + adrmsg^.msgnum + "</td><td valign=\"top\" class=\"small\">" + link + "</td><td align=\"right\" class=\"small\">" + shortDateTime (adrmsg^.postTime) + "</td></tr>");;
					if ct >= 5 {
						break}};
				s = s + "</table>";
				addRow ("Most recent threads", s)};
			addRow ("Stories", adrstats^.ctStories);
			addRow ("Pictures", adrstats^.ctPictures);
			addRow ("News Items", adrstats^.ctNewsItems + " (" + adrstats^.ctNewsItemsPosted + " posted)");
			addRow ("Gems", adrstats^.ctGems + " (" + string.gigabyteString (adrstats^.gemsTotalSizeBytes) + ")");
			addFooter ()};
		bundle { //syndication info
			addHeader ("Syndication");
			bundle { //enabled/disabled
				local (s);
				if manilaSuite.getNewsSitePref ("flSyndicate", adrsite) {
					s = "Enabled"}
				else {
					s = "Disabled"};
				addRow ("Enabled/disabled", s)};
			addRow ("Title", manilaSuite.getNewsSitePref ("rssInfo.channelTitle", adrsite));
			addRow ("Description", manilaSuite.getNewsSitePref ("rssInfo.channelDescription", adrsite));
			addRow ("RSS URL", adrinfo^.siteUrl + "xml/rss.xml");
			addRow ("scriptingNews2 URL", adrinfo^.siteUrl + "xml/scriptingNews2.xml");
			addRow ("Managing editor", string.replace (manilaSuite.getNewsSitePref ("rssInfo.userLandExtensions.managingEditor", adrsite), "@", "\\@"));
			addFooter ()};
		bundle { //search info
			addHeader ("Search");
			local (adrdata = manilaSuite.search.init (adrsite));
			local (flEnabled = adrdata^.flIndex);
			local (server = adrdata^.serverDomain);
			local (flThisMachine = tcp.equalNames (server, tcp.dns.getMyDottedId ()));
			if not flThisMachine {
				flThisMachine = tcp.equalNames (server, "127.0.0.1")};
			bundle { //enabled/disabled
				local (s, cmd);
				if flEnabled {
					s = "Enabled";
					cmd = "disable"}
				else {
					s = "Disabled";
					cmd = "enable"};
				addRow ("Enabled/disabled", s, cmd, thisPageUrl + "&command=" + cmd + "Search")};
			bundle { //search server
				local (s);
				if server == "" {
					s = "not specified"}
				else { //get server info
					s = server + ":" + adrdata^.serverPort;
					local (rpcpath = adrdata^.serverRpcPath);
					if not (rpcpath beginsWith "/") {
						rpcpath = "/" + rpcpath};
					s = s + rpcpath;
					if flThisMachine {
						s = s + "<br /><font size=\"-1\" class=\"small\">(The search engine is running on this server.)</font>"}};
				addRow ("Server", s, "configure", thisPageUrl + "&command=configureSearch")};
			bundle { //RPC procedure
				local (procedure = adrdata^.serverProcedureName);
				addRow ("XML-RPC Index Procedure", procedure)};
			bundle { //dg indexing
				local (s, cmd);
				if adrdata^.flIndexDgMessages {
					s = "Discussion group messages will be indexed";
					cmd = "disable"}
				else {
					s = "Discussion group messages will not be indexed";
					cmd = "enable"};
				addRow ("Discussion Group Indexing", s, cmd, thisPageUrl + "&command=" + cmd + "DgIndexing")};
			bundle { //last full index
				if adrdata^.indexQueue.whenLastIndexCompleted > date (0) {
					addRow ("Last Full Index", adrdata^.indexQueue.whenLastIndexCompleted)}
				else {
					local (note = "");
					if flEnabled {
						note = "<font size=\"-1\" class=\"small\">(This only means that a full index of this site has never been run, however all of the content in this site may have already been incrementally indexed as it was created.)</font>"};
					addRow ("Last Full Index", "never<br />" + note)}};
			bundle { //admin functions
				if flEnabled and (server != "") {
					local (prompt = "Index entire site");
					if adrdata^.indexQueue.flRunning {
						if thread.exists (adrdata^.indexQueue.threadId) {
							addRow (prompt, "This site is in the process of being indexed: " + adrdata^.indexQueue.ctMsgsIndexed + " of " + sizeOf (adrmsgs^) + " messages indexed so far.")}
						else {
							addRow (prompt, "This site was in the process of being indexed, but the index operation has been stopped. To restart the index, click the restart link at the right. (You will be prompted for confirmation.)", "restart", thisPageUrl + "&command=indexSite")}}
					else {
						addRow (prompt, "You can re-index this entire site including pages created before indexing was enabled, by clicking the index link at the right. (You will be prompted for confirmation.)", "index", thisPageUrl + "&command=indexSite")}}
				else {
					addRow ("De-index entire site", "You can de-index pages in this site which were indexed while indexing was enabled, by clicking the de-index link at the right. (You will be prompted for confirmation.)", "de-index", thisPageUrl + "&command=deIndexSite")}};
			addFooter ()};
		bundle { //editors
			addHeader ("Editors");
			local (s);
			on addOneEditor (email) {
				local (edlink = email);
				try {
					local (adrmember = @adrinfo^.adrMembers^.[email]);
					if defined (adrmember^.personalInfo) {
						if defined (adrmember^.personalInfo.name) {
							edlink = adrmember^.personalInfo.name}}};
				edlink = html.getLink (string.replace (edlink, "@", "\\@"), adrinfo^.profilesUrl + email);
				s = s + edlink + ", "};
			on addEditors (editors) {
				if typeOf (editors) == listType {
					local (editor);
					for editor in editors {
						addOneEditor (editor)}}
				else { //only one editor
					addOneEditor (editors)};
				s = string.mid (s, 1, sizeOf (s) - 2);
				return (true)};
			bundle { //managing editors
				s = "";
				local (editors = manilaSuite.getNewsSitePref ("sysopMail", adrsite, "x"));
				if editors != "x" {
					addEditors (editors)};
				addRow ("Managing editors", s, "edit", adrinfo^.siteurl + "admin/sitePrefs/default$editorial")};
			bundle { //contributing editors
				s = "";
				local (editors = manilaSuite.getNewsSitePref ("contributingEditors", adrsite, "x"));
				if editors != "x" {
					addEditors (editors)};
				addRow ("Contributing editors", s, "edit", adrinfo^.siteurl + "admin/sitePrefs/default$editorial")};
			bundle { //content editors
				s = "";
				local (editors = manilaSuite.getNewsSitePref ("contentEditors", adrsite, "x"));
				if editors != "x" {
					addEditors (editors)};
				addRow ("Content editors", s, "edit", adrinfo^.siteurl + "admin/sitePrefs/default$editorial")};
			addFooter ()};
		bundle { //members
			addHeader ("Members");
			addRow ("Total members", sizeOf (adrinfo^.adrMembers^), "list", adrinfo^.siteurl + "stats/members");
			local (ctblocked = 0, adr);
			for adr in adrinfo^.adrMembers {
				if defined (adr^.blocked) {
					if adr^.blocked {
						ctblocked++}}};
			addRow ("Blocked members", ctblocked, "edit", adrinfo^.siteurl + "admin/");
			addFooter ()};
		bundle { //plugins
			local (pluginslist = manilaSuite.plugins.getList ());
			addHeader ("Plugins");
			if sizeOf (pluginslist) > 0 {
				for plugin in pluginsList {
					local (link = plugin);
					local (url = manilaSuite.plugins.getPluginDescriptionUrl (plugin));
					if url != "" {
						link = html.getLink (plugin, url)};
					if manilaSuite.plugins.isEnabled (plugin, pta^.adrSiteRootTable) {
						addRow (link, "Enabled")}
					else {
						addRow (link, "Disabled")}}}
			else { //no plugins installed
				add ("<tr bgcolor=\"" + bgcolor1 + "\"><td colspan=\"2\">There are no plugins installed on this server.</td></tr>")};
			addFooter ()};
		bundle { //stats
			addHeader ("Stats");
			addRow ("Hits all-time", adrinfo^.totalHits);
			addRow ("Hits today", adrinfo^.hitsToday + "   <font size=\"-1\" class=\"small\">(<a href=\"" + adrinfo^.siteurl + "stats/referers\">referers</a>)</font>");
			
			bundle { //5 most read messages
				local (adrstats = @adrdg^.stats);
				if not defined (adrstats^) {
					new (tableType, adrstats)};
				local (adrrankings = @adrstats^.rankings);
				bundle { //compile rankings if necessary
					if not defined (adrrankings^) {
						new (tableType, adrrankings);
						setTimeCreated (adrrankings, date.yesterday (clock.now ()))};
					local (timeCompiled = timeCreated (adrrankings));
					local (midnight);
					local (day, month, year, hour, minute, second);
					date.get (clock.now (), @day, @month, @year, @hour, @minute, @second);
					midnight = date.set (day, month, year, 0, 0, 0);
					if timeCompiled < midnight { //do the stats need to be re-compiled? 
						new (tabletype, adrrankings);
						local (adrmsg);
						for adrmsg in adrmsgs {
							adrrankings^.[nameof (adrmsg^)] = adrmsg^.ctReads};
						local (oldtarget = target.set (adrrankings));
						table.sortBy ("Value");
						try {target.set (oldtarget)}}};
				local (i, adrmsg, ctcounts = sizeOf (adrrankings^), ctlisted = 0);
				local (s = "<table cellpadding=\"2\" cellspacing=\"0\" border=\"0\" width=\"95%\">");
				for i = ctcounts downto 1 {
					ctlisted++;
					adrmsg = @adrmsgs^.[nameof (adrrankings^[i]) ];
					local (link = mainResponder.discuss.linkToMessage (adrmsg, msgReaderUrl));
					s = s + ("<tr><td valign=\"top\" class=\"small\" width=\"15\">" + ctlisted + ".</td><td valign=\"top\" class=\"small\">" + link + "</td><td align=\"right\" class=\"small\">" + adrmsg^.ctReads + " reads</td></tr>");;
					if ctlisted >= 5 {
						break}};
				s = s + "<td></td><td class=\"small\">(<a href=\"" + adrinfo^.siteUrl + "stats/mostReadMessages\">more</a>)</td>";
				s = s + "</table>";
				addRow ("Most read messages", s)};
			addFooter ()}};
	
	return (htmlText)}



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.