simple-discuss/src/view_comments.c

243 lines
5.9 KiB
C
Raw Normal View History

2023-07-03 14:58:09 +03:00
#include "string_buffer.h"
#include "utils.h"
#include "comment.h"
#include "cgic.h"
#include "driver.h"
2023-07-03 16:39:36 +03:00
#include "drivers/unix_fs/unix_fs_driver.h"
#include "config.h"
2023-07-03 14:58:09 +03:00
#include <stdlib.h>
2023-07-03 20:25:23 +03:00
#include <time.h>
2023-07-04 15:34:30 +03:00
#include <stdio.h>
2023-07-03 14:58:09 +03:00
2023-07-03 20:25:23 +03:00
int
page_by_id(int id)
{
return id / COMMENTS_PER_PAGE + 1;
}
2023-07-03 14:58:09 +03:00
void
render_comment(const Comment *comment)
{
char *retval;
2023-07-03 20:25:23 +03:00
int rid;
2023-07-03 14:58:09 +03:00
2023-07-03 20:51:14 +03:00
fprintf(cgiOut, "<div class=\"comment\" id=\"comment_%d\">\n", comment->id);
2023-07-03 14:58:09 +03:00
/* begin header */
2023-07-03 20:51:14 +03:00
fprintf(cgiOut, "<div class=\"comment-header\">\n");
fprintf(cgiOut, "Posted by: %s\n", comment->header->user_displayname);
2023-07-03 20:25:23 +03:00
rid = comment->header->reply_id;
if (rid > 0) {
2023-07-03 20:51:14 +03:00
fprintf(cgiOut, "<a href=\"?page=%d#comment_%d\"> in reply to </a>", page_by_id(rid), rid);
2023-07-03 20:25:23 +03:00
}
2023-07-03 20:51:14 +03:00
fprintf(cgiOut, "</div>\n");
2023-07-03 14:58:09 +03:00
/* end header */
2023-07-03 20:51:14 +03:00
fprintf(cgiOut, "%s", comment->text);
2023-07-03 14:58:09 +03:00
2023-07-03 20:51:14 +03:00
fprintf(cgiOut, "</div>\n");
2023-07-03 14:58:09 +03:00
}
void
allocate_header(CommentHeader *header)
{
header->user_sid = malloc(MAX_NAME_SIZE);
header->user_displayname = malloc(MAX_NAME_SIZE);
2023-07-03 14:58:09 +03:00
}
void
free_header(CommentHeader *header)
{
free(header->user_sid);
free(header->user_displayname);
}
2023-07-03 16:39:36 +03:00
void
allocate_comment(Comment *comment)
{
comment->header = malloc(sizeof(CommentHeader));
allocate_header(comment->header);
}
void
free_comment(Comment *comment)
{
free_header(comment->header);
free(comment->header);
free(comment->text);
}
2023-07-03 14:58:09 +03:00
int
fetch_comment(int id, Driver *driver, void *driver_data, Comment *comment)
{
int retval;
comment->id = id;
2023-07-03 16:39:36 +03:00
allocate_comment(comment);
2023-07-03 14:58:09 +03:00
2023-07-03 16:39:36 +03:00
retval = driver->get_header(driver_data, comment->header, id);
2023-07-03 14:58:09 +03:00
if (retval < 0) {
goto defer;
}
comment->text = malloc(comment->header->text_length + 1);
2023-07-03 16:39:36 +03:00
retval = driver->get_text(driver_data, comment->text, id);
2023-07-03 14:58:09 +03:00
defer:
if (retval < 0) {
2023-07-03 16:39:36 +03:00
free_comment(comment);
2023-07-03 14:58:09 +03:00
}
return retval;
}
2023-07-03 20:25:23 +03:00
void
print_submit_form()
{
2023-07-04 15:34:30 +03:00
fputs("<form action=\"\" method=\"POST\">\n"
2023-07-03 20:25:23 +03:00
"<label>Your name:</label>\n"
"<input type=\"text\" name=\"displayname\"><br>\n"
"<label>Leave comment: </label><br>\n"
"<input type=\"text\" name=\"text\"><br>\n"
"<input type=\"submit\" name=\"submit\" value=\"Submit\">\n"
"</form>\n", cgiOut);
}
2023-07-03 20:48:11 +03:00
/* each page stores comments with ids in [P * (page - 1) + 1, P * page + 1)
2023-07-03 16:39:36 +03:00
* if page is not specified, then we'll just print last P comments (for now)
* TODO: print errors in div
*/
void
print_page()
{
int page, max_id;
int id_begin, id_end, i;
Comment comment;
UnixFsDriverData driver_data = DRIVER_DATA;
Driver driver = DRIVER;
cgiFormInteger("page", &page, 0);
if ((max_id = unix_fs_driver_get_max_id(&driver_data)) < 0) {
fprintf(cgiOut, "Error fetching comments\n");
return;
}
if (page <= 0) {
id_end = max_id;
id_begin = (max_id > COMMENTS_PER_PAGE ? max_id - COMMENTS_PER_PAGE : 1);
} else {
2023-07-03 20:48:11 +03:00
/* max_id > COMMENTS_PER_PAGE * (page - 1) + 1
* max_id - 1 > COMMENTS_PER_PAGE * (page - 1)
2023-07-03 16:39:36 +03:00
* perform this check without overflow
*/
2023-07-03 20:48:11 +03:00
if ((max_id + COMMENTS_PER_PAGE - 1) / COMMENTS_PER_PAGE <= (page - 1)) {
2023-07-03 16:39:36 +03:00
fprintf(cgiOut, "There is no such page\n");
return;
}
2023-07-03 20:48:11 +03:00
id_begin = COMMENTS_PER_PAGE * (page - 1) + 1;
2023-07-03 16:39:36 +03:00
id_end = id_begin + COMMENTS_PER_PAGE;
if (id_end > max_id) {
id_end = max_id;
}
}
for (i = id_begin; i != id_end; ++i) {
if (fetch_comment(i, &driver, &driver_data, &comment) < 0) {
fprintf(cgiOut, "Failed to fetch comment %d\n", i);
} else {
2023-07-03 20:51:14 +03:00
render_comment(&comment);
2023-07-03 16:39:36 +03:00
free_comment(&comment);
}
}
}
2023-07-03 20:25:23 +03:00
/* TODO: restore fields for user no to lose data */
int
handle_submitted_comment()
{
char displayname[MAX_NAME_SIZE], text[MAX_COMMENT_SIZE], *sanitized_text;
2023-07-03 20:25:23 +03:00
int rid, retval;
cgiFormResultType err;
2023-07-03 20:52:50 +03:00
CommentHeader header;
2023-07-03 20:25:23 +03:00
Driver driver = DRIVER;
UnixFsDriverData driver_data = DRIVER_DATA;
err = cgiFormString("text", text, MAX_COMMENT_SIZE);
if (err == cgiFormTruncated) {
fprintf(cgiOut, "Comment too long (max %d bytes)\n", MAX_COMMENT_SIZE);
goto defer;
}
if (err == cgiFormNotFound) {
fprintf(cgiOut, "Comment text not provided\n");
goto defer;
}
err = cgiFormString("displayname", displayname, MAX_NAME_SIZE);
2023-07-03 20:25:23 +03:00
if (err == cgiFormTruncated) {
fprintf(cgiOut, "Name too long (max %d bytes)\n", MAX_NAME_SIZE);
2023-07-03 20:25:23 +03:00
goto defer;
}
if (err == cgiFormNotFound) {
fprintf(cgiOut, "Name not provided\n");
goto defer;
}
if (contain_special(displayname)) {
err = cgiFormTruncated;
fprintf(cgiOut, "Name must not contain HTML special characters\n");
goto defer;
}
cgiFormInteger("reply-to", &rid, 0);
sanitized_text = mk_specialchars(text);
time(&header.creation_time);
header.reply_id = rid;
header.text_length = strlen(sanitized_text);
2023-07-04 15:34:30 +03:00
header.user_sid = "web/anonymous";
2023-07-03 20:25:23 +03:00
header.user_displayname = displayname;
if (driver.leave_comment(&driver_data, &header, sanitized_text) < 0) {
fprintf(cgiOut, "Failed to leave your comment\n");
} else {
fprintf(cgiOut, "Comment successfully left\n");
}
free(sanitized_text);
defer:
return (err == cgiFormSuccess ? 0 : -1);
}
2023-07-03 14:58:09 +03:00
int
cgiMain()
{
cgiHeaderContentType("text/html");
fprintf(cgiOut, "<html>\n");
fprintf(cgiOut, "<head>\n");
2023-07-03 20:25:23 +03:00
fprintf(cgiOut, "<title> Simple discuss powered by qments </title>\n");
2023-07-03 14:58:09 +03:00
fprintf(cgiOut, "</head>\n");
fprintf(cgiOut, "<body>\n");
2023-07-03 20:25:23 +03:00
if (cgiFormSubmitClicked("submit") == cgiFormSuccess) {
handle_submitted_comment();
}
2023-07-03 16:39:36 +03:00
2023-07-03 20:25:23 +03:00
print_submit_form();
2023-07-03 16:39:36 +03:00
fprintf(cgiOut, "<div class=\"comment-section\">\n");
print_page();
fprintf(cgiOut, "</div>\n");
2023-07-03 14:58:09 +03:00
fprintf(cgiOut, "</body>\n");
fprintf(cgiOut, "</html>\n");
return 0;
}