aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Smeding <tom.smeding@gmail.com>2020-07-28 16:05:47 +0200
committerTom Smeding <tom.smeding@gmail.com>2020-07-28 16:07:43 +0200
commit1d28744e532ac73ddff0c6fa829949497b25d4b6 (patch)
tree78cf2b126a75b39dc5a98b6bde5f0a7eb2e2c8ec
parenta9413077b5839b98fc791fcadbae4f8fa1c3743f (diff)
server: Implement get_message
-rw-r--r--command.c57
-rw-r--r--db.c37
-rw-r--r--db.h3
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<ml.count;i++){
- free(ml.list[i].message);
+ db_nullify_message(ml.list[i]);
}
if(ml.list)free(ml.list);
ml.list=NULL;
diff --git a/db.h b/db.h
index 13df899..73d275a 100644
--- a/db.h
+++ b/db.h
@@ -64,10 +64,11 @@ i64 db_create_message(i64 roomid,i64 userid,i64 timestamp,i64 replyid,const char
struct db_message_list db_get_messages(i64 roomid,i64 count); // gets latest `count` messages in rev. chron. order
// if beforeid<0, same as db_get_messages
struct db_message_list db_get_messages_before(i64 roomid,i64 count,i64 beforeid);
-bool db_message_exists(i64 roomid,i64 msgid);
+struct db_message db_get_message(i64 msgid); // returns {msgid=-1} if nonexistent
void db_nullify_name_id(struct db_name_id ni);
void db_nullify_room_list(struct db_room_list rl);
void db_nullify_user_list(struct db_user_list ul);
+void db_nullify_message(struct db_message ml);
void db_nullify_message_list(struct db_message_list ml);
void db_nullify_strings_list(struct db_strings_list sl);