A web-based newsgroup

Try online Examples

This shows that Aptilis is well at ease when it comes to fairly complex tasks. Here is how to implement a web-based discussion forum...
Even the Aptilis Forums are based on the original code!

Much credit goes to Steven de Brouwer for having fixed many quirks in that script.

sub Init()

	// Here we initialize all the values we will need all over the application.
	// remember that variable names starting with an underscore are global to the
	// whole program. Ie. once defined, they can be seen in all the subs.


	_scriptURL = "http://localhost/cgi-bin/aptilis.exe" $
	_scriptPath = "f:/projects/aptilis/documentation/targets/local/scripts/newsgroup.e.txt" $
	_articlesPath = "c:/temp/aptilis/" $

	if right(_articlesPath$, 1) = "/" $
		_articlesPath = left(_articlesPath$, len(_articlesPath$) - 1) $
	end if

	// To notify me of any posting.
	setSmtpServer("smtp.ntlworld.com")


end Init



sub AddButton(command, face, addition)

	// This sub adds a button, in effect a complete form.

	print("<FORM action=\"", _scriptURL$, "\" method=\"POST\" target=\"article\">\n")
	print("<INPUT type=\"hidden\" name=\"file\" value=\"", _scriptPath$, "\">\n")
	print("<INPUT type=\"hidden\" name=\"cmd\" value=\"", command$, "\">\n")

	print(addition$)

	print("<CENTER><INPUT type=\"submit\" value=\"", face$, "\"></CENTER>\n")
	print("</FORM>\n")

end AddButton



sub NewPostingForm(a, m)


	print("<BODY bgColor=\"#FFFFFF\">\n")


	if len(a$) > 0
		// This is a reply, we need to load the article.

		ChangeDirectory(_articlesPath$)
		file = loadFile(a$)$

		n = separate(lines[], file$, "\n")
		file = "" $

		print("<TABLE border=1><TR><TD valign=top><B> Reply")
		if m = 1
			print(" and Mail")
		end if
		print(" To:</B></TD><TD>")
		print(lines[2]$, "</TD></TR>\n")

		if len(trim(lines[1]$)$) = 0
			name = "[Anonymous]" $
		else
			name = lines[1]$
		end if


		print("<TR><TD>by:</TD><TD>")
		if len(lines[0]$)
			print("<I><A href=\"mailto:", lines[0]$, "\">")
		end if

		print(name$)

		if len(lines[0]$)
			print("</A>")
		end if

		print("</I></TD></TR></TABLE>\n<HR>\n\n")

		content = "" $
		for i = 3 to n - 1
			content = content + "> " + replace(lines[i]$, "\r", "") + "\n" $
		end for

		title = replace("Re: " + lines[2]$, "\"", "'") $

	else
		print("<B>Post new article</B><HR><P>")
	end if



	print("<FORM action=\"", _scriptURL$, "\" method=\"POST\">\n")
	print("<INPUT type=\"hidden\" name=\"file\" value=\"", _scriptPath$, "\">\n")
	print("<INPUT type=\"hidden\" name=\"cmd\" value=\"30\">\n")
	print("<INPUT type=\"hidden\" name=\"a\" value=\"", a$, "\">\n")
	print("<INPUT type=\"hidden\" name=\"m\" value=\"", m$, "\">\n")

	print("<TABLE>")

	print("<TR><TD><B>Title of Posting:</B></TD>\n")
	print("<TD><INPUT type=\"text\" name=\"title\" Value=\"", title$, "\" size=20></TD></TR>\n")

	print("<TR><TD valign=top><B>Posting:</B></TD>\n")
	print("<TD><TEXTAREA name=\"posting\" cols=50 ROWS=10>", content$, "</TEXTAREA></TD></TR>\n")

	print("<TR><TD valign=top><B>Your e-mail:</B></TD>\n")
	print("<TD><INPUT type=\"text\" name=\"email\" size=50></TD></TR>\n")

	print("<TR><TD valign=top><B>Your name:</B></TD>\n")
	print("<TD><INPUT type=\"text\" name=\"name\" size=50></TD></TR>\n")


	print("<TR><TD></TD><TD><INPUT type=\"submit\" value=\"Post article\"></TD></TR>\n")
	print("</TABLE>\n\n")

	print("</FORM>\n\n")
	print("</BODY>\n")


end NewPostingForm



sub AddPosting(title, posting, email, name, a, m)

// <I>the 'posting' and 'a' variables come directly from the form.</I>


	// <I>To remove those **** carriage returns from PCs...</I>
	posting = replace(posting$, "\r", "") $


	// <I>To be sure that those are only one line</I>
	// <I>Otherwise we might not put the information where it should be...</I>
	email = replace(email$, "\r" ,"") $
	email = replace(email$, "\n", " ") $
	name = replace(name$, "\r", "") $
	name = replace(name$, "\n", " ") $
	title = replace(title$, "\r", "") $
	title = replace(title$, "\n", " ") $


	// <I>The file we are going to create will have this format:</I>
	// <I>line 0: email</I>
	// <I>line 1: name</I>
	// <I>line 2: title</I>
	// <I>line 3 and after: the posting</I>


	if len(name$) = 0
		name = email $
	end if


	total = email + "\n" + name + "\n" + title + "\n" + posting $


	changeDirectory(_articlesPath$)

	if len(a$) = 0


		// Find a file name: this is a new posting.
		t = gettime()
		fillLocalTimeArray(date[], t)
		d = int(date[6]) $
		d = string(3 - len(d$), "0") + d $

		serial = 0
		repeat

			serial = int(serial) $
			s = string(3 - len(serial$), "0") + serial $

			filename = path + d + s + "-.txt" $
			serial = serial + 1

		until fileExist(filename$) = -1

	else
		// This is a reply to an existing posting.


		// We need to load the file in order to send a reply to the orginal poster it if requested.
		if m = 1
			file = loadFile(a$)$
			n = separate(lines[], file$, "\n")
			file = "" $
			if len(lines[0]$) > 0
				sendmail(lines[0]$, "teebo@glaine.net", "Aptilis Test Neswgroup - Reply to " + title$, posting$)
			end if
		end if


		p = instr(a$, "-") $
		d = left(a$, p - 1) $

		serial = 0
		repeat

			serial = int(serial) $
			s = string(3 - len(serial$), "0") + serial$
			filename = path + d + s + "-.txt" $
			serial = serial + 1

		until fileExist(filename$) = -1

	end if



	// ...And finally, save the posting.
	savefile(filename$, total$)

end AddPosting



sub DisplayFiles


	if ChangeDirectory(_articlesPath$) = -1
		print("Impossible to reach the Postings' repository: ", _articlesPath$, "<BR>")
		print("Errno: ", _errno$, "<BR>")
		return
	end if


	// Because of the way the names of the articles
	// are created, sorting them in alphabetical order
	// puts them in the right order for the display.

	n = GetFileList(fl[], "*.txt")
	sortarray(fl[], "alphabetical")

	// Display the entries


	print("<UL>\n")
	l = 2
	for i=0 to n - 1

		nl = (instr(fl[i]$, "-") -1) / 3
		bcl = nl

		while bcl < l
			print("</UL>\n")
			bcl = bcl + 1
		end while

		while bcl > l
			print("<UL>\n")
			bcl = bcl-1
		end while

		DisplayEntry(fl[i]$)
		l = nl

	end for
	print("</UL>\n")


end DisplayFiles



sub DisplayEntry(f)

	file = loadFile(f$) $
	n = separate(l[], file$, "\n")

	// <I>We don't need this anymore, let's save memory</I>
	file = "" $


	// <I>We want to be sure to have all the fields!</I>
	if n < 3
		return 0
	end if


	print("<LI><B><A href=\"", _scriptURL$, "?")
	print("file=", _scriptPath$, "&cmd=40&a=", f$, "\" target=\"article\">")
	print("[", l[2]$, "]</A>")


	for i=0 to 2
		lens[i] = Len(l[i]$)
	end for



	// <I>Put the Author's name, if any</I>
	if lens[1]
		print(" - ", l[1]$)
	end if

	print("</B> (", int( GetFileSize(f$) - lens[0] - lens[1] - lens[2] - 2)$, " chars)")
	print("</LI>\n")

end DisplayEntry



sub DisplayPosting(a)

	// This sub displays a single Posting in it's entirety.

	print("<BODY bgColor=\"#FFFFFF\">\n\n")

	changeDirectory(_articlesPath$)
	file = loadFile(a$) $

	n = separate(lines[], file$, "\n") $
	file = "" $


	print("<B>", lines[2]$, "</B><BR>\n")

	if len(lines[0]$)
		print("By <I><A href=\"mailto:", lines[0]$, "\">")
		print(lines[1]$, "</A></I>\n<HR>\n\n")
	end if


	print("<PRE>")
	for i = 3 to n - 1
		// The original line feeds have been removed by LoadDatabase but there might be some CRs
		s = replace(lines[i]$,">","&gt;") $
		s = replace(s$,"<","&lt;") $
		print(s$, "\n")
	end for

	print("</PRE>\n\n")


	// The buttons
	print("<CENTER><TABLE><TR><TD bgcolor=#00C000>")

	add = "<INPUT type=\"hidden\" name=\"m\" value=0>\n<INPUT type=\"hidden\" name=\"a\" value=\"" + a + "\">\n" $
	AddButton("20", "Reply Only", add$)

	print("</TD><TD bgcolor=#0000C0>")

	add = "<INPUT type=\"hidden\" name=\"m\" value=1>\n<INPUT type=\"hidden\" name=\"a\" value=\"" + a + "\">\n" $
	AddButton("20", "Reply + Mail", add$)

	print("</TD></TR></TABLE></CENTER>\n\n")
	print("</BODY>\n")


end DisplayPosting



sub main

	// To initialize all our necessary values.
	Init()

	// Magic line!
	print("Content-Type: text/html\n\n")



	// Common to everything we will be doing.
	print("<HTML>\n<HEAD>\n\t<TITLE>Aptilis Demo News-Group</TITLE>\n\t<BASE href=\"", _Base$, "\">\n</HEAD>\n\n")



	// We use a variable, cmd, to decide what to do.
	select cmd
	case 0
		// Display the Frameset.
		print("<FRAMESET COLS=\"30%,*\">\n")
		print("    <FRAME SRC=\"", _scriptURL$, "?file=", _scriptPath$, "&cmd=10\" NAME=\"plist\">\n")
		print("    <FRAME SRC=\"", _scriptURL$, "?file=", _scriptPath$, "&cmd=5\" NAME=\"article\">\n")
		print("</FRAMESET>\n\n")
		break

	case 5
		// Entry screen.
		print("<BODY bgColor=\"#FFFFFF\">\n")
		print("<TABLE width=100% height=100%><TR><TD vAlign=center align=center><FONT Face=\"Arial,Helvetica\"><IMG Src=\"http://www.aptilis.com/res/aptilis-tiny.gif\" Alt=\"Aptilis\"><BR>Demo Newsgroup</FONT></TD></TR></TABLE>\n\n")
		print("</BODY>\n")
		break

	case 10
		// List all Postings in left hand frame.
		print("<BODY bgColor=\"#FFFFFF\">\n")

		print("<HR><CENTER><IMG Src=\"http://www.aptilis.com/res/aptilis-tiny.gif\" Alt=\"Aptilis\"></CENTER><HR>\n")
		AddButton("20", "Post Something", "")
		DisplayFiles()

		print("</BODY>\n")
		break

	case 20
		// Article Form.
		NewPostingForm(a$, m$)
		break

	case 30
		// Add Posting.
		AddPosting(title$, posting$, email$, name$, a$, m$)
		print("<BODY>Thanks for your posting.\n\n")

		// We use a hidden form and some javaScript to refresh the list of Postings.
		print("<FORM Action=\"", _scriptURL$, "\" Method=\"Post\" Target=\"plist\" Name=\"ngrfh\">\n")
		print("<INPUT Type=\"hidden\" Name=\"file\" Value=\"", _scriptPath$, "\">\n")
		print("<INPUT Type=\"hidden\" Name=\"cmd\" Value=\"10\">\n")
		print("</FORM>\n\n")

		print("<SCRIPT Language=\"javaScript\">\n<!--\ndocument.ngrfh.submit()\n//-->\n</SCRIPT></BODY>")
		break

	case 40
		// Display a single posting.
		DisplayPosting(a$)
		break

	end select



	print("</HTML>\n")

end main