From e21ad3a5aa46635db9dc30b3395aa59588074932 Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Mon, 27 Jul 2020 21:22:42 +0200 Subject: server: Protocol v2, DB v2: message replies --- db.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) (limited to 'db.c') diff --git a/db.c b/db.c index 0de620d..416b9d3 100644 --- a/db.c +++ b/db.c @@ -10,7 +10,8 @@ #define SQLITE(func,...) do{if(sqlite3_##func(__VA_ARGS__)!=SQLITE_OK){die_sqlite("sqlite3_" #func);}}while(0) -#define DATABASE_VERSION 1 +#define DATABASE_VERSION 2 + #define PASSHASH_OPSLIMIT 3 #define PASSHASH_MEMLIMIT crypto_pwhash_MEMLIMIT_INTERACTIVE @@ -381,16 +382,18 @@ bool db_delete_token(i64 userid,const char *token){ } -i64 db_create_message(i64 roomid,i64 userid,i64 timestamp,const char *message){ +i64 db_create_message(i64 roomid,i64 userid,i64 timestamp,i64 replyid,const char *message){ sqlite3_stmt *stmt; SQLITE(prepare_v2,database, - "insert into Messages (room, user, time, message) " - "values (?, ?, ?, ?)" + "insert into Messages (room, user, time, reply, message) " + "values (?, ?, ?, ?, ?)" ,-1,&stmt,NULL); SQLITE(bind_int64,stmt,1,roomid); SQLITE(bind_int64,stmt,2,userid); SQLITE(bind_int64,stmt,3,timestamp); - SQLITE(bind_blob,stmt,4,message,strlen(message),SQLITE_STATIC); + if(replyid>=0)SQLITE(bind_int64,stmt,4,replyid); + else SQLITE(bind_null,stmt,4); + SQLITE(bind_blob,stmt,5,message,strlen(message),SQLITE_STATIC); if(sqlite3_step(stmt)!=SQLITE_DONE)die_sqlite("sqlite3_step"); SQLITE(finalize,stmt); @@ -407,7 +410,7 @@ struct db_message_list db_get_messages_before(i64 roomid,i64 count,i64 beforeid) sqlite3_stmt *stmt; if(beforeid<0){ SQLITE(prepare_v2,database, - "select id, user, time, message " + "select id, user, time, reply, message " "from Messages " "where room = ? " "order by time desc " @@ -417,7 +420,7 @@ struct db_message_list db_get_messages_before(i64 roomid,i64 count,i64 beforeid) SQLITE(bind_int64,stmt,2,count); } else { SQLITE(prepare_v2,database, - "select id, user, time, message " + "select id, user, time, reply, message " "from Messages " "where room = ? and time < (select time from Messages where id = ?) " "order by time desc " @@ -442,7 +445,12 @@ struct db_message_list db_get_messages_before(i64 roomid,i64 count,i64 beforeid) ml.list[ml.count].roomid=roomid; ml.list[ml.count].userid=sqlite3_column_int64(stmt,1); ml.list[ml.count].timestamp=sqlite3_column_int64(stmt,2); - ml.list[ml.count].message=strdup((const char*)sqlite3_column_text(stmt,3)); + if(sqlite3_column_type(stmt,3)==SQLITE_INTEGER){ + ml.list[ml.count].replyid=sqlite3_column_int64(stmt,3); + } else { + ml.list[ml.count].replyid=-1; // NULL, not a reply + } + ml.list[ml.count].message=strdup((const char*)sqlite3_column_text(stmt,4)); ml.count++; } @@ -452,6 +460,18 @@ struct db_message_list db_get_messages_before(i64 roomid,i64 count,i64 beforeid) return ml; } +bool db_message_exists(i64 roomid, i64 msgid) { + sqlite3_stmt *stmt; + SQLITE(prepare_v2, database, + "select id from Messages where id = ? and room = ?", + -1, &stmt, NULL); + SQLITE(bind_int64, stmt, 1, msgid); + SQLITE(bind_int64, stmt, 2, roomid); + bool success = sqlite3_step(stmt) == SQLITE_ROW; + SQLITE(finalize, stmt); + return success; +} + void db_nullify_name_id(struct db_name_id ni){ if(ni.name)free(ni.name); -- cgit v1.2.3-70-g09d2 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(-) (limited to 'db.c') 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