/* Change this to point to the location where you want comments to be kept on your system! The file must be writable by the web server. */ #define COMMENT_FILE "/CHANGE/THIS/PATH/comments.txt" #include #include /* Global variables */ /* This example can only process up to 100 input fields in a single form. Of course, we know that this form only has a handful. Change this #define if you need more, or use the cgic library, which has no such limitations. */ #define FIELDS_MAX 100 char *names[FIELDS_MAX]; char *values[FIELDS_MAX]; int fieldsTotal = 0; /* Makes sure this request is a form submission */ int VerifyForm(); /* Parses the submitted form data, filling the names[] and values[] arrays with useful information */ void ParseForm(); /* Frees the memory associated with the form data. */ void FreeForm(); /* Copies src to dst, unescaping any special characters in the process. dst must be at least as large as src in order to ensure that there is enough space. */ void UnescapeString(char *dst, char *src); int main(int argc, char *argv[]) { FILE *out; int i; int nameIndex = -1, emailIndex = -1, commentsIndex = -1; printf("Content-type: text/html\n\n"); printf("\n"); printf("\n"); /* Make sure it's a POST-method form submission */ if (!VerifyForm()) { printf("Not a POST Form Submission\n"); printf("\n"); printf("

Not a POST Form Submission

\n"); printf("This page should be accessed only by submitting\n"); printf("a form using the POST method. Perhaps your\n"); printf("browser does not support forms.\n"); printf("\n"); return 0; } /* OK, it's a form submission, so parse it. */ ParseForm(); /* Use the information */ /* Find the index of each field in the arrays */ for (i = 0; (i < fieldsTotal); i++) { if (!strcmp(names[i], "name")) { nameIndex = i; } else if (!strcmp(names[i], "email")) { emailIndex = i; } else if (!strcmp(names[i], "comments")) { commentsIndex = i; } } /* If any field is missing, complain! */ if ((nameIndex == -1) || (emailIndex == -1) || (commentsIndex == -1)) { printf("Please fill out all the fields\n"); printf("\n"); printf("

Please fill out all the fields

\n"); printf("Please fill out the name, email address, AND\n"); printf("comment fields. Back up to the previous page\n"); printf("to try again.\n"); printf("\n"); return 0; } /* OK, we have all the data. Write it to a file in which we collect comments from users. Open to append, of course. */ out = fopen(COMMENT_FILE, "a"); fprintf(out, "From: %s <%s>\n", values[nameIndex], values[emailIndex]); fprintf(out, "%s\n", values[commentsIndex]); printf("Thank you, %s\n", values[nameIndex]); printf("\n"); printf("

Thank you, %s

\n", values[nameIndex]); printf("Thank you for your comments.\n"); printf("\n"); /* Free the memory we used */ FreeForm(); return 0; } int VerifyForm() { char *contentType; char *requestMethod; int bad = 0; /* Check the content type of the data we've received */ contentType = getenv("CONTENT_TYPE"); if (strcmp(contentType, "application/x-www-form-urlencoded") != 0) { bad = 1; } /* And make sure the POST method was used */ requestMethod = getenv("REQUEST_METHOD"); if (strcmp(requestMethod, "POST") != 0) { bad = 1; } return !bad; } /* Parses the submitted form data, filling the names[] and values[] arrays with useful information */ void ParseForm() { char *contentLength = getenv("CONTENT_LENGTH"); /* The number of characters in the data */ int length; /* The buffer into which we read the data */ char *buffer; /* The current position in the buffer while we search for separators */ char *p; /* Determine the length of the input */ if (!contentLength) { length = 0; } else { length = atoi(contentLength); } /* Allocate a buffer to store the input in. Include space for one extra character to make the parsing loop simpler. */ buffer = (char *) malloc(length + 1); if (!buffer) { /* Uh-oh */ return; } /* Read all the data from standard input */ if (fread(buffer, 1, length, stdin) != length) { /* Uh-oh */ return; } p = buffer; while (length) { /* The beginning of the current name */ char *name; /* The beginning of the current value */ char *value; int found; /* Make sure we have room for more fields. */ if (fieldsTotal == FIELDS_MAX) { /* Uh-oh, can't accept any more */ return; } name = p; /* First, find an equal sign. */ found = 0; while (length) { if (*p == '=') { /* End the name with a null character. */ *p = '\0'; p++; found = 1; break; } p++; length--; } if (!found) { /* A blank or truncated entry. Strange, but web browsers are unpredictable; be tolerant. */ break; } value = p; /* Now, find an ampersand. */ found = 0; while (length) { if (*p == '&') { /* End the value with a null character. */ *p = '\0'; p++; found = 1; break; } p++; length--; } if (!found) { /* Assume that this is the end of the last entry. */ *p = '\0'; } /* Allocate space for the name and value in those arrays, then call UnescapeString to unescape and copy them. Be sure to allow space for the final null character. */ names[fieldsTotal] = (char *) malloc(strlen(name) + 1); if (!names[fieldsTotal]) { /* Uh-oh, no memory. Return with what we do have. */ return; } values[fieldsTotal] = (char *) malloc(strlen(value) + 1); if (!values[fieldsTotal]) { /* Uh-oh, no memory. Return with what we do have. */ free(names[fieldsTotal]); return; } /* Copy the strings, un-escaping them in the process. */ UnescapeString(names[fieldsTotal], name); UnescapeString(values[fieldsTotal], value); fieldsTotal++; /* Continue, finding more pairs. */ } /* Free the buffer we used. */ free(buffer); } void FreeForm() { int i; for (i=0; (i < fieldsTotal); i++) { free(names[i]); free(values[i]); } } void UnescapeString(char *dst, char *src) { /* Loop over the characters in the string until we encounter the null character at the end, which tests false. */ while (*src) { char c; c = *src; /* Handle spaces escaped as + signs */ if (c == '+') { c = ' '; } else if (c == '%') { /* Handle % escapes */ char hexdigits[3]; int ascii; src++; if (!*src) { /* Digits missing! Ignore escape */ break; } hexdigits[0] = *src; src++; if (!*src) { /* Digits missing! Ignore escape */ break; } hexdigits[1] = *src; /* Add a terminating null... */ hexdigits[2] = '\0'; /* Now use the C standard library function sscanf() to read the hex value */ sscanf(hexdigits, "%x", &ascii); /* And convert it back to a character */ c = ascii; } *dst = c; src++; dst++; } *dst = '\0'; }