From 1d28744e532ac73ddff0c6fa829949497b25d4b6 Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Tue, 28 Jul 2020 16:05:47 +0200 Subject: server: Implement get_message --- command.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- db.c | 37 +++++++++++++++++++++++++++++++------ db.h | 3 ++- 3 files changed, 85 insertions(+), 12 deletions(-) diff --git a/command.c b/command.c index ba8727e..ca70d76 100644 --- a/command.c +++ b/command.c @@ -257,9 +257,13 @@ static struct cmd_retval cmd_send(struct conn_data *data,const char *tag,const c net_send_error(data->fd,tag,"Not in that room"); return RET_OK; } - if(replyid>=0&&!db_message_exists(roomid,replyid)){ - net_send_error(data->fd,tag,"Replied-to message not found"); - return RET_OK; + if(replyid>=0){ + struct db_message msg=db_get_message(replyid); + if(msg.msgid==-1){ + net_send_error(data->fd,tag,"Replied-to message not found"); + return RET_OK; + } + db_nullify_message(msg); } i64 timestamp=make_timestamp(); @@ -361,6 +365,48 @@ static struct cmd_retval cmd_history_before(struct conn_data *data,const char *t return history_cmd_helper(data,tag,args,"history_before",beforeid); } +static struct cmd_retval cmd_get_message(struct conn_data *data, const char *tag, const char **args) { + i64 msgid; + if (!parse_i64(args[0], &msgid)) { + debug("Connection fd=%d sent an invalid number for 'get_message': '%s'", + data->fd, args[0]); + return RET_CLOSE(true); + } + + if (data->userid == -1) { + net_send_error(data->fd, tag, "Not logged in"); + return RET_OK; + } + + struct db_message msg = db_get_message(msgid); + if (msg.msgid == -1) { + net_send_error(data->fd, tag, "Message not found"); + return RET_OK; + } + + if (!db_is_member(msg.roomid, data->userid)) { + db_nullify_message(msg); + // Don't disclose that the message actually exists elsewhere + net_send_error(data->fd, tag, "Message not found"); + return RET_OK; + } + + char *roomname = db_get_roomname(msg.roomid); + char *username = db_get_username(msg.userid); + + char *buf = NULL; + i64 len = asprintf(&buf, "%s message %s %s %" PRIi64 " %" PRIi64 " %" PRIi64 " %s\n", + tag, roomname, username, msg.timestamp, msg.msgid, msg.replyid, msg.message); + free(roomname); + free(username); + + bool closed = net_send_raw_text(data->fd, buf, len); + free(buf); + + db_nullify_message(msg); + return RET_CLOSE(closed); +} + static struct cmd_retval cmd_ping(struct conn_data *data,const char *tag,const char **args){ (void)args; return RET_CLOSE(net_send_pong(data->fd,tag)); @@ -419,8 +465,8 @@ struct cmd_info{ // Use CommandHash.hs to re-generate this perfect hash function for a different // list of commands. -#define COMMAND_HASH_MODULUS 31 -#define COMMAND_HASH(cmd0, len) ((cmd0 + 6 * len) % COMMAND_HASH_MODULUS) +#define COMMAND_HASH_MODULUS 34 +#define COMMAND_HASH(cmd0, len) ((4 * cmd0 + 7 * len) % COMMAND_HASH_MODULUS) #define COMMAND_ENTRY(cmd0, cmd, nargs, longlast, handler) \ [COMMAND_HASH(cmd0, strlen(cmd))] = {cmd, nargs, longlast, handler} @@ -439,6 +485,7 @@ static const struct cmd_info commands[COMMAND_HASH_MODULUS] = { COMMAND_ENTRY('s', "send", 3, true, cmd_send), COMMAND_ENTRY('h', "history", 2, false, cmd_history), COMMAND_ENTRY('h', "history_before", 3, false, cmd_history_before), + COMMAND_ENTRY('g', "get_message", 1, false, cmd_get_message), COMMAND_ENTRY('p', "ping", 0, false, cmd_ping), COMMAND_ENTRY('i', "is_online", 1, false, cmd_is_online), COMMAND_ENTRY('f', "firebase_token", 1, false, cmd_firebase_token), diff --git a/db.c b/db.c index 416b9d3..d94b13c 100644 --- a/db.c +++ b/db.c @@ -460,16 +460,37 @@ struct db_message_list db_get_messages_before(i64 roomid,i64 count,i64 beforeid) return ml; } -bool db_message_exists(i64 roomid, i64 msgid) { +struct db_message db_get_message(i64 msgid) { sqlite3_stmt *stmt; SQLITE(prepare_v2, database, - "select id from Messages where id = ? and room = ?", + "select room, user, time, reply, message " + "from Messages where id = ?", -1, &stmt, NULL); SQLITE(bind_int64, stmt, 1, msgid); - SQLITE(bind_int64, stmt, 2, roomid); - bool success = sqlite3_step(stmt) == SQLITE_ROW; + + struct db_message msg; + if (sqlite3_step(stmt) == SQLITE_ROW) { + msg.msgid = msgid; + msg.roomid = sqlite3_column_int64(stmt,0); + msg.userid = sqlite3_column_int64(stmt,1); + msg.timestamp = sqlite3_column_int64(stmt,2); + if (sqlite3_column_type(stmt, 3) == SQLITE_INTEGER) { + msg.replyid = sqlite3_column_int64(stmt, 3); + } else { + msg.replyid = -1; // NULL, not a reply + } + msg.message = strdup((const char*)sqlite3_column_text(stmt, 4)); + } else { + msg.msgid = -1; + msg.roomid = -1; + msg.userid = -1; + msg.timestamp = -1; + msg.replyid = -1; + msg.message = NULL; + } + SQLITE(finalize, stmt); - return success; + return msg; } @@ -493,9 +514,13 @@ void db_nullify_user_list(struct db_user_list ul){ ul.list=NULL; } +void db_nullify_message(struct db_message msg){ + if(msg.message)free(msg.message); +} + void db_nullify_message_list(struct db_message_list ml){ for(i64 i=0;i