Posted By

Zufolek on 08/30/09


Tagged


Versions (?)

CGI guestbook


 / Published in: C
 

A simple guestbook. Compile c file to exe, put in /cgi-bin/ with txt files. Tested with TinyWeb server found here: http://www.ritlabs.com/en/products/tinyweb/

  1. /**** Beginning of file guestbook.c ****/
  2.  
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <conio.h>
  7. #include <ctype.h>
  8. #include <time.h>
  9.  
  10.  
  11. /* here are the names of data files needed */
  12. char*header="header.txt";
  13. char*guestbook="guestbook.txt";
  14. char*footer="footer.txt";
  15.  
  16. /* this will hold 0 or a message for the user */
  17. char*msg=0;
  18.  
  19.  
  20. /* data structure for one cgi parameter */
  21. typedef struct{
  22. char*name;
  23. char*value;
  24. } Arg;
  25.  
  26.  
  27.  
  28. /* prints error message to stdout and commits seppuku */
  29. void err(char*s){
  30. puts("Guestbook has encountered an error!");
  31. puts(s);
  32. exit(1);
  33. }
  34.  
  35.  
  36. /* returns value of one hex digit */
  37. int getHex(char c){
  38. if(isdigit(c))return c-'0';
  39. if(isalpha(c))return tolower(c)-'a'+10;
  40. return 0;
  41. }
  42.  
  43.  
  44. /* decodes 1 character from hex*/
  45. char decode(char*s){
  46. return getHex(s[0])*16+getHex(s[1]);
  47. }
  48.  
  49.  
  50. /* to prevent making tags in html */
  51. int safeChar(char c){
  52. switch(c){
  53. case '<':
  54. case '>':
  55. return 0;
  56. }
  57. return 1;
  58. }
  59.  
  60.  
  61. /* returns 1 if s points to 2 valid consecutive hex digits */
  62. int isSafe(char*s){
  63. if(!isxdigit(s[0]) || !isxdigit(s[1])) return 0;
  64. return 1;
  65. }
  66.  
  67.  
  68. /* decodes hex values, converts + to space,
  69.  and converts newline to <br> */
  70. char*fixData(char*i){
  71. int l=strlen(i);
  72. char*m=malloc(l*4+8);
  73. char*o=m;
  74. if(!m)err("Memory allocation failure for fixData");
  75. while(*i){
  76. if(*i=='+')*o=' ';
  77. else if(*i=='%'&&isSafe(i+1)){
  78. char d=decode(i+1);
  79. if(safeChar(d)){
  80. if(d=='\n')o+=sprintf(o,"<br>")-1;
  81. else if(d=='\r')--o;
  82. else *o=d;
  83. }else o+=sprintf(o,"&#%d;",d)-1;
  84. i+=2;
  85. }else *o=*i;
  86. ++i;
  87. ++o;
  88. }
  89. *o=0;
  90. m=realloc(m,o-m+1);
  91. if(!m)err("Memory reallocation failure for fixData");
  92. return m;
  93. }
  94.  
  95.  
  96. /* prints a basic http header to stdout */
  97. void init(){
  98. printf("Content-Type: text/html\n\n");
  99. }
  100.  
  101.  
  102. /* gets input string from stdin */
  103. char*getInput(){
  104. char*v=getenv("CONTENT_LENGTH");
  105. char*s=0;
  106. if(v){
  107. int l=atoi(v);
  108. if(l){
  109. s=malloc(l+1);
  110. FILE*f=stdin;
  111. if(!s)err("Memory allocation failure for input");
  112. fread(s,1,l,f);
  113. s[l]=0;
  114. }
  115. }
  116. return s;
  117. }
  118.  
  119.  
  120. /* returns count of variables encoded in string */
  121. int countVars(char*s){
  122. int n=1;
  123. while(*s){
  124. if(*s=='&')++n;
  125. ++s;
  126. }
  127. return n;
  128. }
  129.  
  130.  
  131. /* Moves pointer-pointer s just past next occurrence of character c,
  132.  which is then set to 0, or returns 1 if end of string is reached */
  133. int skipTo(char**s,char c){
  134. while(**s != c){
  135. if(!**s)return 1;
  136. ++*s;
  137. }
  138. **s=0;
  139. ++*s;
  140. return 0;
  141. }
  142.  
  143.  
  144. /* Parses input string for args */
  145. Arg*parseInput(char*s){
  146. int l=countVars(s);
  147. Arg*arg=malloc((l+1)*sizeof(Arg));
  148. Arg*a=arg;
  149. if(!a)err("Memory allocation failure for args list");
  150. while(*s){
  151. a->name=s;
  152. if(skipTo(&s,'='))goto Done;
  153. a->value=s;
  154. if(skipTo(&s,'&'))goto Done;
  155. ++a;
  156. }
  157. Done:
  158. arg[l].name=0;/* marks the end of arg list */
  159. return arg;
  160. }
  161.  
  162.  
  163. /* returns cgi parameter in array a that has name==s */
  164. char*getArg(Arg*a,char*s){
  165. while(a->name){
  166. if(!strcmp(a->name,s))return fixData(a->value);
  167. ++a;
  168. }
  169. return "";
  170. }
  171.  
  172.  
  173. /* returns 1 if parameter list has required inputs */
  174. int isValid(Arg*a){
  175. char*s1=getArg(a,"name");
  176. char*s2=getArg(a,"text");
  177. int b=*s1 && *s2;
  178. free(s1);
  179. free(s2);
  180. return b;
  181. }
  182.  
  183.  
  184. /* saves posted message to guestbook data file */
  185. void saveOutput(Arg*a){
  186. FILE*f=fopen(guestbook,"at");
  187. char*s;
  188. if(!f)err("Can't save file!");
  189. s=getArg(a,"name");
  190. fprintf(f,"<p><div class=txt><b>%s</b>\n",s);
  191. free(s);
  192. {
  193. time_t rawtime;
  194. struct tm*timeinfo;
  195. time(&rawtime);
  196. timeinfo=localtime(&rawtime);
  197. fprintf(f,"&nbsp;%s<br><hr>",asctime(timeinfo));
  198. }
  199. s=getArg(a,"text");
  200. fprintf(f,"%s",s);
  201. free(s);
  202. fputs("</div>\n\n",f);
  203. fclose(f);
  204. }
  205.  
  206.  
  207. /* prints a file to stdout */
  208. void showFile(char*s){
  209. FILE*f=fopen(s,"rt");
  210. if(f){
  211. while(1){
  212. char c=getc(f);
  213. if(c==EOF)break;
  214. putchar(c);
  215. }
  216. fclose(f);
  217. }
  218. }
  219.  
  220.  
  221. /* prints whole page to stdout */
  222. void showOutput(){
  223. showFile(header);
  224. if(msg)puts(msg);
  225. showFile(guestbook);
  226. showFile(footer);
  227. }
  228.  
  229.  
  230. int main(){
  231. char*i;
  232. Arg*a;
  233. init();
  234. i=getInput();
  235. if(i){
  236. a=parseInput(i);
  237. if(isValid(a)){
  238. saveOutput(a);
  239. msg="Your message has been added!";
  240. }else msg="Invalid input!";
  241. free(i);
  242. free(a);
  243. }
  244. showOutput(a);
  245. return 0;
  246. }
  247.  
  248.  
  249. /**** End of file guestbook.c ****/
  250.  
  251. /**** Beginning of file header.txt ****/
  252.  
  253. <html><head><title>Guestbook</title><style>
  254. body,.txt,input,textarea,button{color:#fff;background-color:#000;font:16px verdana}
  255. textarea{width:90%;height:256px}
  256. .txt{background-color:#008}
  257. .txt{border:1px solid #0f0;padding:4px}
  258. </style></head><body>
  259.  
  260. /**** End of file header.txt ****/
  261.  
  262. /**** Beginning of file footer.txt ****/
  263.  
  264. <p><form action="guestbook.exe" method=post>
  265. <center>Name:<br><input name=name maxlength=32><p>
  266. Message:<br><textarea name=text></textarea>
  267. <p><input type=submit value="Post">
  268. </form></center></body></html>
  269.  
  270. /**** End of file footer.txt ****/

Report this snippet  

You need to login to post a comment.