aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Ankarström <john@ankarstrom.se>2021-09-18 22:51:30 +0200
committerJohn Ankarström <john@ankarstrom.se>2021-09-18 22:51:44 +0200
commit9ff1b81d65c370a938cd9d9c033e04e395f00704 (patch)
tree3f507a48d8d39f27a36b3fab32b0a230abe512f4
parent2b915a42f6665b4110338cfde30eedc55abe7f3c (diff)
downloadcforum-9ff1b81d65c370a938cd9d9c033e04e395f00704.tar.gz
New user
-rw-r--r--Makefile2
-rw-r--r--README19
-rw-r--r--ctl.c82
-rw-r--r--db.c44
-rw-r--r--db.h4
-rw-r--r--query.c11
-rw-r--r--site.h19
-rw-r--r--t/front.t3
-rw-r--r--t/head.t8
-rw-r--r--t/newuser.t35
-rw-r--r--t/post.t2
11 files changed, 210 insertions, 19 deletions
diff --git a/Makefile b/Makefile
index 93275cb..0c9ab3a 100644
--- a/Makefile
+++ b/Makefile
@@ -33,5 +33,5 @@ db:
sqlite3 db "CREATE TABLE posts(parent INT, user INT NOT NULL, created INT NOT NULL, edited INT, subject NOT NULL, text NOT NULL, FOREIGN KEY (user) REFERENCES users(oid));"
sqlite3 db "INSERT INTO posts values(NULL, 1, 1462137896, NULL, 'Hello World!', 'This is the first post.');"
sqlite3 db "INSERT INTO posts values(1, 1, 1462138896, NULL, 'Re: Hello World!', 'This is the second post!');"
- sqlite3 db "CREATE TABLE atts(post INT NOT NULL, name NOT NULL, description, mime NOT NULL, data BLOB, FOREIGN KEY (post) REFERENCES posts(oid));"
+ sqlite3 db "CREATE TABLE atts(post INT NOT NULL, name NOT NULL, desc, mime NOT NULL, data BLOB, FOREIGN KEY (post) REFERENCES posts(oid));"
sqlite3 db "$$(printf "INSERT INTO atts values(1, 'example', 'Some example shell code.', 'text/plain', '#!/bin/sh\necho Hello World!');")" \ No newline at end of file
diff --git a/README b/README
index 63ca7e0..8030d7f 100644
--- a/README
+++ b/README
@@ -8,21 +8,22 @@ C89, it can be run on practically any UNIX system.
It is also rather small:
wc -l *.c *.h */*.t */*.lex
- 100 cforum.c
- 143 ctl.c
- 230 db.c
+ 101 cforum.c
+ 223 ctl.c
+ 268 db.c
10 err.c
- 106 query.c
+ 113 query.c
6 ctl.h
40 db.h
0 err.h
14 query.h
- 2 site.h
+ 21 site.h
3 t/err.t
1 t/foot.t
- 26 t/front.t
- 6 t/head.t
+ 29 t/front.t
+ 14 t/head.t
+ 34 t/newuser.t
28 t/post.t
12 t/user.t
- 87 mktpl/mktpl.lex
- 814 total
+ 95 mktpl/mktpl.lex
+ 1012 total
diff --git a/ctl.c b/ctl.c
index 64934cc..e4b25a7 100644
--- a/ctl.c
+++ b/ctl.c
@@ -1,3 +1,4 @@
+#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -35,7 +36,86 @@ newpost()
void
newuser()
-{}
+{
+ char *confirm, *hlite, *msg, *name, *full, *p, *pass, *v;
+ char title[] = "New User";
+
+ if(!(msg = malloc(128)))
+ err(1, "malloc");
+
+ *msg = 0;
+ confirm = hlite = name = full = pass = NULL;
+
+ if(query.method == GET){
+ printf("Content-Type: text/html\n\n");
+ #include "t/newuser.tc"
+ return;
+ }
+
+ while(p = nextparam(POST, MAXUSERPARAM)){
+ if(!(v = split(p))) continue;
+
+ if(!confirm && strcmp(p, "confirm") == 0)
+ confirm = strdup(v);
+ else if(!name && strcmp(p, "name") == 0)
+ name = strdup(v);
+ else if(!full && strcmp(p, "full") == 0)
+ full = strdup(v);
+ else if(!pass && strcmp(p, "pass") == 0)
+ pass = strdup(v);
+ else
+ continue;
+
+ if(TRUNCATED(p)){
+ hlite = strdup(p);
+ snprintf(msg, 128,
+ "Input length exceeds server limitations");
+ goto err;
+ }
+ }
+
+ /* Ensure all required fields are there. */
+ if(!name || !*name || !pass || !*pass){
+ hlite = (!name || !*name)? strdup("name"): strdup("pass");
+ snprintf(msg, 128, "Required field missing");
+ goto err;
+ }
+
+ /* Decode URL-encoded fields. */
+
+ /* Restrain lengths of decoded fields. */
+ if(name && *name && strlen(name)-1 > MAXUSERNAME){
+ hlite = strdup("name");
+ snprintf(msg, 128, "Username longer than %d characters",
+ MAXUSERNAME-1);
+ goto err;
+ }
+ if(full && *full && strlen(full)-1 > MAXUSERFULL){
+ hlite = strdup("full");
+ snprintf(msg, 128, "Full name longer than %d characters",
+ MAXUSERFULL-1);
+ goto err;
+ }
+ if(pass && *pass && strlen(pass)-1 > MAXUSERPASS){
+ hlite = strdup("pass");
+ snprintf(msg, 128, "Password longer than %d characters",
+ MAXUSERPASS-1);
+ goto err;
+ }
+
+ if(pass && confirm && strcmp(pass, confirm) != 0){
+ snprintf(msg, 128, "Passwords do not match");
+ goto err;
+ }
+
+ printf("Content-Type: text/html\n\n");
+ printf("You are valid\n");
+ return;
+err:
+ printf("Content-Type: text/html\n\n");
+ #include "t/newuser.tc"
+ return;
+}
/*
* The `show' functions show an existing attachment/post/user
diff --git a/db.c b/db.c
index cf75ec6..a6391a6 100644
--- a/db.c
+++ b/db.c
@@ -17,7 +17,7 @@ addatt(struct att *att)
sqlite3_stmt *stmt;
if(sqlite3_prepare(db, "INSERT INTO atts"
- " (post, name, description, mime, data)"
+ " (post, name, desc, mime, data)"
" VALUES (?, ?, ?, ?, ?)",
-1, &stmt, 0) != SQLITE_OK)
goto err;
@@ -30,7 +30,7 @@ addatt(struct att *att)
!= SQLITE_OK)
goto err;
- if(sqlite3_bind_text(stmt, 3, att->description, -1, SQLITE_STATIC)
+ if(sqlite3_bind_text(stmt, 3, att->desc, -1, SQLITE_STATIC)
!= SQLITE_OK)
goto err;
@@ -53,6 +53,44 @@ err:
}
int
+addpost(struct post *post)
+{
+ sqlite3_stmt *stmt;
+
+ if(sqlite3_prepare(db, "INSERT INTO posts"
+ " (parent, user, created, subject, text)"
+ " VALUES (?, ?, ?, ?, ?)",
+ -1, &stmt, 0) != SQLITE_OK)
+ goto err;
+
+ if(sqlite3_bind_int(stmt, 1, post->parent) != SQLITE_OK)
+ goto err;
+
+ if(sqlite3_bind_int(stmt, 2, post->user) != SQLITE_OK)
+ goto err;
+
+ if(sqlite3_bind_int(stmt, 3, post->created) != SQLITE_OK)
+ goto err;
+
+ if(sqlite3_bind_text(stmt, 4, post->subject, -1, SQLITE_STATIC)
+ != SQLITE_OK)
+ goto err;
+
+ if(sqlite3_bind_text(stmt, 5, post->text, -1, SQLITE_STATIC)
+ != SQLITE_OK)
+ goto err;
+
+ if(sqlite3_step(stmt) != SQLITE_DONE)
+ goto err;
+
+ sqlite3_finalize(stmt);
+ return 1;
+err:
+ sqlite3_finalize(stmt);
+ return 0;
+}
+
+int
adduser(struct user *user)
{
sqlite3_stmt *stmt;
@@ -141,7 +179,7 @@ nextatt(sqlite3_stmt *stmt)
att->id = sqlite3_column_int(stmt, 0);
att->post = sqlite3_column_int(stmt, 1);
att->name = strdupn(sqlite3_column_text(stmt, 2));
- att->description = strdupn(sqlite3_column_text(stmt, 3));
+ att->desc = strdupn(sqlite3_column_text(stmt, 3));
att->mime = strdupn(sqlite3_column_text(stmt, 4));
att->bytes = sqlite3_column_bytes(stmt, 5);
diff --git a/db.h b/db.h
index d6f229d..1385b98 100644
--- a/db.h
+++ b/db.h
@@ -5,9 +5,9 @@ sqlite3 *db;
struct att{
int id;
int post;
- int bytes;
+ int bytes; /* Size of data. */
char *name;
- char *description;
+ char *desc;
char *mime;
char *data;
};
diff --git a/query.c b/query.c
index 7947d59..370fa54 100644
--- a/query.c
+++ b/query.c
@@ -6,8 +6,9 @@
/*
* Return an allocated string containing the next query string parameter
- * ("key=value"). The string is truncated to max characters. If truncation
- * occurred, the -1th character of the string is set to 1.
+ * ("key=value"). The string is truncated to max characters (but is always
+ * NUL-terminated). If truncation occurred, the -1th character of the string
+ * is set to 1.
*/
char *
nextparam(enum method method, int max)
@@ -104,4 +105,10 @@ split(char *param)
return NULL;
param[n] = 0;
return param+n+1;
+}
+
+void
+urldecode(char *s)
+{
+
} \ No newline at end of file
diff --git a/site.h b/site.h
index f590bad..4e13319 100644
--- a/site.h
+++ b/site.h
@@ -1,3 +1,22 @@
+/*
+ * TODO: It is probably better to use the CONTENT_LENGTH
+ * environment variable to decide the length of the entire
+ * posted query string and then compare it to a max value,
+ * such as:
+ */
+
+#define MAXATTDATA 4096
+#define MAXUSERDATA 512
+#define MAXPOSTDATA 4096
+
+/* Maximum size of newuser parameter, incl. NUL. */
+#define MAXUSERPARAM 512
+
+/* Maximum size of user information, incl. NUL. */
+#define MAXUSERNAME 80
+#define MAXUSERFULL 128
+#define MAXUSERPASS 128
+
struct site{
char *name;
} site; \ No newline at end of file
diff --git a/t/front.t b/t/front.t
index 9d39469..2662be2 100644
--- a/t/front.t
+++ b/t/front.t
@@ -1,5 +1,8 @@
<% #include "head.tc" %>
<h1><%= site.name %></h1>
+<ul>
+ <li><a href="?new=user">Sign up</a></li>
+</ul>
<h3>Latest posts</h3>
<table border="1">
<% while(post = nextpost(pstmt)){
diff --git a/t/head.t b/t/head.t
index d9da813..7962c5b 100644
--- a/t/head.t
+++ b/t/head.t
@@ -3,5 +3,13 @@
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title><%= title %></title>
+<style type="text/css">
+ form.hlite-confirm #confirm,
+ form.hlite-name #name,
+ form.hlite-full #full,
+ form.hlite-pass #pass {
+ background: #f66;
+ }
+</style>
</head>
<body> \ No newline at end of file
diff --git a/t/newuser.t b/t/newuser.t
new file mode 100644
index 0000000..a0a0dd9
--- /dev/null
+++ b/t/newuser.t
@@ -0,0 +1,35 @@
+<% #include "head.tc" %>
+<h1>New User</h1>
+<% if(*msg){ %>
+<p style="color: red;"><%= msg %></p>
+<% } %>
+<form class="<% if(hlite) printf("hlite-%s", hlite); %>" action="?new=user" method="POST">
+ <table border="0">
+ <tr id="name">
+ <td><label for="name">Username</label></td>
+ <td><input type="text" name="name" value="<% if(name) printf("%s", name); %>"></td>
+ </tr>
+ <tr id="full">
+ <td><label for="full">Full Name</label></td>
+ <td><input type="text" name="full" value="<% if(full) printf("%s", full); %>"></td>
+ <td><small>(optional)</small></td>
+ </tr>
+ <tr id="pass">
+ <td><label for="pass">Password</label></td>
+ <td><input type="password" name="pass" value=""></td>
+ </tr>
+ <tr id="confirm">
+ <td><label for="confirm">Confirm</label></td>
+ <td><input type="password" name="confirm" value=""></td>
+ </tr>
+ </table>
+ <p>By clicking <i>Create</i>, you confirm</p>
+ <ol>
+ <li>that this user is a real human,</li>
+ <li>that you will not abuse the service,</li>
+ <li>that the information you provide will be saved on the server, and</li>
+ <li>that your user may be terminated by an administrator at any point and for any reason.</li>
+ </ol>
+ <p><input type="submit" value="Create &rarr;"></p>
+</form>
+<% #include "foot.tc" %> \ No newline at end of file
diff --git a/t/post.t b/t/post.t
index 1e3d360..e30ddbe 100644
--- a/t/post.t
+++ b/t/post.t
@@ -20,7 +20,7 @@
<tr>
<td><a href="?att=<% printf("%d", att->id); %>"><%= att->name %></a></td>
<td><%= att->mime %></td>
- <td><%= att->description %></td>
+ <td><%= att->desc %></td>
</tr>
<% free(att);
}while(att = nextatt(stmt)); %>