Google Sites Comments
If you use Google Sites (like I do) you know there is no good way to allow guests to leave comments or discuss your pages. The more popular choice it to use a combination of Google Documents spreadsheet and a form. This leaves a clunky ugly spreadsheet on the bottom of your page. Not the best choice. I am not saying my solution is the best either, but it suits my needs and has a cleaner look. Plus it is free.
If you have access to a server you can run CGI on you can use this set up. I have a Linux web server running in my home office on normal cable modem. Not the ideal choice for hosting a web site due to speed and port availability (i.e. port 80 is blocked.) However with the use of a dynamic DNS service it is a satisfactory solution for running the comments CGI script.
Google Sites will allow you to embed an external CGI page into your Sites page by using IFRAME.
<iframe name="foo" src="yourserver/cgibin/bar.cgi?read=filename></iframe>
Filename is where you choose what to call the text file that will hold the comments for that page.
It will look like all other Google Sites Widgets in the editor but will look clean when viewed.
I have attached a modified version of the C code I wrote.
The key features are:
One compiled program handles all pages.
Automatically creates text files for the comments.
Converts HTTP/URL escape characters to ascii.
Small foot print on the server.
No HTML files to maintain.
Basics:
CGI program takes in the Query String and determines whether and where to write the comments to. If we are going to write a comment, remove the escape codes from the URL string. Write them to the appropriate file. Display the comment form. Display the comments.
It is really that easy. I used more lines of code than needed doing silly pointer things, but it is pretty basic. If you want to use it, add your own level of error checking and security as you chose.
Thanks Kyle for some bug finding!
CODE:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void cleaner(char *htmlEncoded);
char hexToAscii(char temp[3]);
main()
{
char *strg,*temp;
char delim[] = "/";
char txt[] = ".txt";
char operation[64], cp[1024], fileStrng[64], name[128], comment[1024],timeStmp[26];
int pos;
printf("content-type: text/html\n\n"); /*Required for browser*/
strg=getenv("QUERY_STRING"); /* get the vars from the browser formated like--- write=pagename&name=username& comment=comment (for a submision) */
/* Make sure YOUR page is calling this -- -optional */
if(getenv("REMOTE_HOST")!="yourforwardingDDNS.com")
return 0;
/* set the file name of the comments to the page it is for */
char filename[64] = "/cgi-bin/comments/";
strcpy(cp,strg); /* copy Query String */
temp = strtok(cp,"&"); /*First element of Query String */
strcpy(cp,temp);
temp= strtok(cp,"="); /* separate the name from the value i.e. read=mypage first we get 'read' then the 'mypage' */
strcpy(operation,temp);
temp=strtok(NULL,"=");
strcpy(fileStrng,temp); /*save this for adding a 'hidden' field on the html form */
strcpy(cp,temp); /* make a full file name */
strcat(cp,txt);
strcat(filename,cp);
/* If we are submitting a comment ... */
if(strcmp(operation,"write")==0)
{
strcpy(cp,strg); /* copy Query String */
temp = strtok(cp,"&"); /*First element of Query String --- we dont care here*/
temp = strtok(NULL,"&"); /*Second element of Query String this will have the 'name=usename' */
strcpy(name,temp);
temp = strtok(NULL,"&"); /*Third element of Query String this will have 'comment=blahblahblah' */
strcpy(comment,temp);
temp = strtok(name,"="); /* look at 'name=username' and seperate 'name' from 'username' */
while(temp!=NULL)
{
strcpy(name,temp); /* if the user doesnt type in a name this will be 'name' (error check later) else it is their username */
temp = strtok(NULL,"=");
}
temp=name; //Send it off to have the escape codes removed
cleaner(temp);
strcpy(name,temp);
temp = strtok(comment,"="); /* same process as name is used for the comment */
while(temp!=NULL)
{
strcpy(comment,temp);
temp= strtok(NULL,"=");
}
temp=comment;
cleaner(temp);
strcpy(comment,temp);
time_t rawtime; /*load up local time for the date stamp */
time ( &rawtime );
if(strcmp(name,"name")==0 || strcmp(comment,"comment")==0) /* error check for blank name or comment */
{
printf("<font color=\"red\">You must enter a Name and Comment</font><p>");
}
else
{
FILE *file = fopen ( filename, "a+" ); /* open the file and append a html table containing the comment line
remove the '+' if you dont want it to
create the file automatically*/
if (file != NULL)
{
fprintf(file,"%s%s%s%s%s%s%s","<table border=\"0\"><tr><td width=\"25%\">",ctime(&rawtime),"</td><td width=\"15%\">",name,"<td><td width=\"60%\">",comment,"</td><p><hr>");
fclose (file);
}
else
{
//printf some error message here about file not loading
}
}
}
/* hard coded HTML form to be displayed*/
printf("<FORM ACTION=\"/cgi-bin/comment.cgi\" method=\"get\">Name:<br><input type=\"HIDDEN\" name=\"write\" value=\"%s\">",fileStrng);
printf("<input type=\"text\" name=\"name\"><p>Comment:<br><TEXTAREA name=\"comment\" cols=\"40\" rows=\"3\"></TEXTAREA><p><input type=\"submit\" value=\"Submit\"></FORM><p>");
/* open, read, and display the comments file*/
FILE *file = fopen ( filename, "r" );
if ( file != NULL )
{
char line [ 128 ];
while ( fgets ( line, sizeof line, file ) != NULL )
{
printf("%s", line);
}
fclose ( file );
}
else
{
//printf some error message here about file not loading
}
/* free our pointers for good measure*/
free(temp);
free(strg);
}
void cleaner(char *htmlEncoded)
{
int pos, pos2,term;
char tmp[4],input,hold[1024];
int first, second, final;
term = strlen(htmlEncoded);
for(pos=0;pos<strlen(htmlEncoded);pos++) //step char by char through the string
{
input=htmlEncoded[pos]; //grab one char at a time
if (input=='+') //remove + replace with spaces
input=' ';
if (input=='%') //escape code starts with % then hex --- %34 = "
{
strncpy(tmp,htmlEncoded+pos,3); //grab the %HH
input=hexToAscii(tmp); //convert string HH to int then to char
pos+=2; //advance two more spaces to eliminate the HH
if(input==13) // Special case - CR and LF -- HTML has no use for CRLF replace it with <BR> 13=CR 10=LF
{
hold[pos2]='<';
pos2++;
hold[pos2]='B';
pos2++;
hold[pos2]='R';
pos2++;
input='>';
}
if(input==10)
input=' ';
}
hold[pos2]=input; //write the char to a temp string
pos2++;
}
hold[term]='\0';
strcpy(htmlEncoded,hold);
}
char hexToAscii(char *tmp) //convert string of two HEX values to INT then to a CHAR
{
int first,second,final;
char ascii;
first = tmp[1]; //first value %H0 - getting the H
first-=48; //the char '0' is equal to 48 decimal, subtract 48 from the int value of the char '0' you get decimal 0
if(first>9) //if the value is higher than 9 it was not a number to start, but a letter A-F
first-=7; // A is 65, 65-48=17 subtract 7 more and A = 10 the right hex value in dec
second = tmp[2];
second-=48;
if(second>9)
second-=7;
final = (first * 16)+second; //first * 16 makes the hex values a byte rather than two nibbles
ascii=final;
return ascii;
}