summaryrefslogtreecommitdiffstats
path: root/prijave.c
diff options
context:
space:
mode:
Diffstat (limited to 'prijave.c')
-rw-r--r--prijave.c104
1 files changed, 85 insertions, 19 deletions
diff --git a/prijave.c b/prijave.c
index c9edb56..8a9b3f0 100644
--- a/prijave.c
+++ b/prijave.c
@@ -41,7 +41,9 @@ enum action {
NO_ACTION,
CREATE_POLL,
FIND_POLLS,
- MODIFY_POLL
+ MODIFY_POLL,
+ DELETE_POLL,
+ ADD_QUESTION
};
struct request {
struct MHD_PostProcessor * post_processor;
@@ -59,6 +61,8 @@ static enum MHD_Result iterator (void * userdata, enum MHD_ValueKind kind __attr
ACTION_TRANSLATION("cp", CREATE_POLL);
ACTION_TRANSLATION("fp", FIND_POLLS);
ACTION_TRANSLATION("mp", MODIFY_POLL);
+ ACTION_TRANSLATION("dp", DELETE_POLL);
+ ACTION_TRANSLATION("aq", ADD_QUESTION);
#define OBTAIN_PARAMETER(name) \
if (!strcmp(key, STR(name))) { \
if (request->name) { \
@@ -104,7 +108,9 @@ static char * options (sqlite3 * db, sqlite3_int64 id, int poll_admin, enum ques
// id obrazca, ime obrazca, število vprašanj v stolpcu
// SELECT polls.rowid, polls.name, COUNT(*) FROM polls INNER JOIN questions ON questions.poll = polls.rowid GROUP BY questions.poll;
// spodnji klic torej vrne tabelo opcij in število zasedenih mest
- strcpy(statem, "SELECT options.rowid, options.text, options.max, COUNT(*) FROM options INNER JOIN responses ON responses.answer=options.rowid GROUP BY responses.answer WHERE options.question=:i");
+ // see TODO#1
+ // strcpy(statem, "SELECT options.rowid, options.text, options.max, COUNT(*) FROM options INNER JOIN responses ON responses.answer=options.rowid GROUP BY responses.answer WHERE options.question=:i");
+ strcpy(statem, "SELECT rowid, text, max FROM options WHERE question=:i;");
if ((ret = sqlite3_prepare_v3(db, statem, -1, 0, &stmt, NULL)) != SQLITE_OK)
return hscf(db_error(db, "options prepare", ret, stmt, statem));
if ((ret = sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, ":i"), id)) != SQLITE_OK)
@@ -114,7 +120,7 @@ static char * options (sqlite3 * db, sqlite3_int64 id, int poll_admin, enum ques
long long int rowid = sqlite3_column_int64(stmt, 0);
char * text = htmlspecialchars((const char *) sqlite3_column_text(stmt, 1));
int max = sqlite3_column_int(stmt, 2);
- int responses = sqlite3_column_int(stmt, 3);
+ // int responses = sqlite3_column_int(stmt, 3);
char * old = response;
response = realloc(response, (strlen(text ? text : "")+2048)*2);
if (!response) {
@@ -124,7 +130,7 @@ static char * options (sqlite3 * db, sqlite3_int64 id, int poll_admin, enum ques
return strdup("[err @ options] oom");
}
if (poll_admin)
- sprintf(response+strlen(response), "<li><form method=post><button type=submit name=do value=%lld>izbriši možnost</button><input type=reset /><input type=submit name=mq value='shrani možnost' /><br><label for=t>besedilo možnosti</label><br><textarea name=t id=t placeholder=besedilo>%s</textarea><br><label for=o>omejitev prijav na možnost (-1 za neomejeno)</label> <input type=number min=-1 step=1 placeholder=številka value=%d /><br>število odgovorov: %d</form></li>", rowid, text ? text : "", max, responses);
+ sprintf(response+strlen(response), "<li><form method=post><button type=submit name=do value=%lld>izbriši možnost</button><input type=reset /><input type=submit name=mq value='shrani možnost' /><br><label for=t>besedilo možnosti</label><br><textarea name=t id=t placeholder=besedilo>%s</textarea><br><label for=o>omejitev prijav na možnost (-1 za neomejeno)</label> <input type=number min=-1 step=1 placeholder=številka value=%d /></form></li>", rowid, text ? text : "", max);
else
sprintf(response+strlen(response), "not implemented");
free(text);
@@ -140,7 +146,9 @@ static char * questions (sqlite3 * db, sqlite3_int64 id, int poll_admin) {
int ret;
char statem[2048];
sqlite3_stmt * stmt;
- strcpy(statem, "SELECT questions.rowid, questions.text, questions.type, COUNT(*) FROM questions INNER JOIN responses ON responses.question=questions.rowid WHERE questions.poll=:i GROUP BY responses.question");
+ // TODO#1: fix number of responses: this does not work if there are no responses for a question. I could use LEFT OUTER JOIN but then NULLs are treated as same value
+ // strcpy(statem, "SELECT questions.rowid, questions.text, questions.type, COUNT(*) FROM questions INNER JOIN responses ON responses.question=questions.rowid WHERE questions.poll=:i GROUP BY responses.question");
+ strcpy(statem, "SELECT rowid, text, type FROM questions WHERE poll=:i");
if ((ret = sqlite3_prepare_v3(db, statem, -1, 0, &stmt, NULL)) != SQLITE_OK)
return hscf(db_error(db, "questions prepare", ret, stmt, statem));
if ((ret = sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, ":i"), id)) != SQLITE_OK)
@@ -150,7 +158,7 @@ static char * questions (sqlite3 * db, sqlite3_int64 id, int poll_admin) {
long long int rowid = sqlite3_column_int64(stmt, 0);
char * text = htmlspecialchars((const char *) sqlite3_column_text(stmt, 1));
enum question type = sqlite3_column_int(stmt, 2);
- int responses = sqlite3_column_int(stmt, 3);
+ // int responses = sqlite3_column_int(stmt, 3);
char * opts = options(db, id, poll_admin, type);
char * old = response;
response = realloc(response, (strlen(response ? response : "")+strlen(text ? text : "")+strlen(opts ? opts : "")+2048)*2);
@@ -162,7 +170,7 @@ static char * questions (sqlite3 * db, sqlite3_int64 id, int poll_admin) {
return strdup("[err @ questions] oom");
}
if (poll_admin)
- sprintf(response+strlen(response), "<li><form method=post><button type=submit name=dq value=%lld>izbriši vprašanje</button><input type=reset /><input type=submit name=mq value='shrani vprašanje' /><br><textarea name=te placeholder=opis>%s</textarea><br><label for=r>radio</label><input type=radio id=r name=ty value=r /><label for=c>kljukica</label><input type=radio id=c name=ty value=c /><label for=v>prosto besedilo</labe><input type=radio id=v name=ty value=v /><label for=h>skrij vprašanje in začasno onemogoči vnos</label><input type=radio id=h name=ty value=h /></form>število odgovorov: %d<ul>%s%s</ul></li>", rowid, text ? text : "", responses, opts ? "<h3>možnosti</h3>" : "", opts ? opts : "");
+ sprintf(response+strlen(response), "<li><form method=post><button type=submit name=dq value=%lld>izbriši vprašanje</button><input type=reset /><input type=submit name=mq value='shrani vprašanje' /><br><textarea name=te placeholder=opis>%s</textarea><br><input type=radio id=r name=ty value=r /><label for=r>radio</label><input type=radio id=c name=ty value=c /><label for=c>kljukica</label><input type=radio id=v name=ty value=v /><label for=v>prosto besedilo</label><input type=radio id=h name=ty value=h /><label for=h>skrij vprašanje</label></form><ul>%s%s</ul></li>", rowid, text ? text : "", opts ? "<h3>možnosti</h3>" : "", opts ? opts : "");
else
sprintf(response+strlen(response), "not implemented");
free(opts);
@@ -175,6 +183,24 @@ static char * questions (sqlite3 * db, sqlite3_int64 id, int poll_admin) {
}
return response;
}
+static char * auth (struct prijave * prijave, const char * pass, long long int id) {
+ int ret;
+ char statem[2048];
+ if (pass && prijave->pass && !strcmp(pass, prijave->pass))
+ return NULL; // system admin password authentication
+ sqlite3_stmt * stmt;
+ strcpy(statem, "SELECT rowid FROM polls WHERE rowid=:i AND password=:pw;");
+ if ((ret = sqlite3_prepare_v3(prijave->db, statem, -1, 0, &stmt, NULL)) != SQLITE_OK)
+ return db_error(prijave->db, "502: auth prepare", ret, stmt, statem);
+ if ((ret = sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, ":i"), id)) != SQLITE_OK)
+ return db_error(prijave->db, "502: auth bind_int64 id", ret, stmt, statem);
+ if ((ret = sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":pw"), pass, -1, SQLITE_STATIC)) != SQLITE_OK)
+ return db_error(prijave->db, "502: auth bind_text password", ret, stmt, statem);
+ if ((ret = sqlite3_step(stmt)) != SQLITE_ROW)
+ return db_error(prijave->db, "403: auth step", ret, stmt, statem);
+ sqlite3_finalize(stmt);
+ return NULL;
+} // returns an error string that must be freed on error or NULL on success
static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connection, const char * path, const char * meth, const char * ver __attribute__((unused)), const char * upload, size_t * upload_size, void ** cls) {
struct prijave * prijave = (struct prijave *) userdata;
char * response = prijave->hp ? prijave->hp : "HTTP 502: httpd !prijave->hp\n";
@@ -295,32 +321,28 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio
goto r;
}
strcpy(statem, "INSERT INTO polls (password, name, description) VALUES (:pw, :n, :d);");
- ret = sqlite3_prepare_v3(prijave->db, statem, -1, 0, &stmt, NULL);
- if (ret != SQLITE_OK) {
+ if ((ret = sqlite3_prepare_v3(prijave->db, statem, -1, 0, &stmt, NULL)) != SQLITE_OK) {
free(response);
RETURN_ERROR("CREATE_POLL prepare");
}
- ret = sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":pw"), request->pp, -1, SQLITE_STATIC);
- if (ret != SQLITE_OK) {
+ if ((ret = sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":pw"), request->pp, -1, SQLITE_STATIC)) != SQLITE_OK) {
free(response);
RETURN_ERROR("CREATE_POLL bind_text password");
}
- ret = sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":n"), request->pn, -1, SQLITE_STATIC);
- if (ret != SQLITE_OK) {
+ if ((ret = sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":n"), request->pn, -1, SQLITE_STATIC)) != SQLITE_OK) {
free(response);
RETURN_ERROR("CREATE_POLL bind_text name");
}
- ret = sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":d"), request->pd, -1, SQLITE_STATIC);
- if (ret != SQLITE_OK) {
+ if ((ret = sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":d"), request->pd, -1, SQLITE_STATIC)) != SQLITE_OK) {
free(response);
RETURN_ERROR("CREATE_POLL bind_text description");
}
- ret = sqlite3_step(stmt);
- sqlite3_finalize(stmt);
- if (ret != SQLITE_DONE) {
+ if ((ret = sqlite3_step(stmt)) != SQLITE_DONE) {
+ sqlite3_finalize(stmt);
free(response);
RETURN_ERROR("CREATE_POLL step");
}
+ sqlite3_finalize(stmt);
status_code = MHD_HTTP_SEE_OTHER;
rmm = MHD_RESPMEM_MUST_FREE;
// THREADSAFE: the following call to sqlite3_last_insert_rowid is racy. it's not a security issue, but if another poll is created before sqlite3_last_insert_rowid is called, the client gets a faulty id that will not work, though he can still solve the problem by using FIND_POLLS.
@@ -418,7 +440,51 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio
sqlite3_finalize(stmt);
response = "HTTP 201: MODIFY_POLL\n";
goto r;
-
+ case DELETE_POLL:
+ strcpy(statem, "DELETE FROM polls WHERE rowid=:i AND (password=:pw OR 1=");
+ if (prijave->pass && pass && !strcmp(prijave->pass, pass))
+ strcat(statem, "1)");
+ else
+ strcat(statem, "0)");
+ if ((ret = sqlite3_prepare_v3(prijave->db, statem, -1, 0, &stmt, NULL)) != SQLITE_OK)
+ RETURN_ERROR("DELETE_POLL prepare");
+ if ((ret = sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, ":i"), id)) != SQLITE_OK)
+ RETURN_ERROR("DELETE_POLL bind_int64 id");
+ if ((ret = sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":pw"), pass, -1, SQLITE_STATIC)) != SQLITE_OK)
+ RETURN_ERROR("DELETE_POLL bind_text password");
+ if ((ret = sqlite3_step(stmt)) != SQLITE_DONE)
+ QUERY_FAILED("DELETE_POLL");
+ sqlite3_finalize(stmt);
+ free_location = 0;
+ location = "?dp";
+ rmm = MHD_RESPMEM_PERSISTENT;
+ response = "HTTP 201: DELETE_POLL\n";
+ content_type = "text/plain; charset=UTF-8";
+ status_code = MHD_HTTP_SEE_OTHER;
+ goto r;
+ case ADD_QUESTION:
+ ;
+ char * auth_ret;
+ if ((auth_ret = auth(prijave, pass, id))) {
+ rmm = MHD_RESPMEM_MUST_FREE;
+ response = auth_ret;
+ content_type = "text/plain; charset=UTF-8";
+ status_code = MHD_HTTP_FORBIDDEN;
+ goto r;
+ }
+ sprintf(statem, "INSERT INTO questions (poll, type) VALUES (%lld, %d);", id, HIDDEN);
+ if ((ret = sqlite3_prepare_v3(prijave->db, statem, -1, 0, &stmt, NULL)) != SQLITE_OK)
+ RETURN_ERROR("ADD_QUESTION prepare");
+ if ((ret = sqlite3_step(stmt)) != SQLITE_DONE)
+ RETURN_ERROR("ADD_QUESTION step");
+ sqlite3_finalize(stmt);
+ location = (char *) MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Referer");
+ free_location = 0;
+ rmm = MHD_RESPMEM_PERSISTENT;
+ response = "HTTP 201: ADD_QUESTION\n";
+ content_type = "text/plain; charset=UTF-8";
+ status_code = MHD_HTTP_SEE_OTHER;
+ goto r;
}
if (id_string) {
if (prijave->pass && pass && !strcmp(pass, prijave->pass)) {