aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--command.c31
-rw-r--r--command.h4
-rw-r--r--db.c36
-rw-r--r--db.h4
-rw-r--r--event.c3
-rw-r--r--event.h3
6 files changed, 60 insertions, 21 deletions
diff --git a/command.c b/command.c
index 8fa343d..ba8727e 100644
--- a/command.c
+++ b/command.c
@@ -232,8 +232,18 @@ static struct cmd_retval cmd_send(struct conn_data *data,const char *tag,const c
return RET_OK;
}
userdata_mark_active(data->userid,data->fd,true);
+
const char *roomname=args[0];
- const char *message=args[1];
+
+ i64 replyid;
+ if(!parse_i64(args[1],&replyid)){
+ debug("Connection fd=%d sent an invalid number for 'send': '%s'",
+ data->fd,args[1]);
+ return RET_CLOSE(true);
+ }
+
+ const char *message=args[2];
+
if(strlen(message)>MAX_MESSAGE_LEN){
net_send_error(data->fd,tag,"Message too long");
return RET_OK;
@@ -247,17 +257,22 @@ 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;
+ }
i64 timestamp=make_timestamp();
- i64 msgid=db_create_message(roomid,data->userid,make_timestamp(),message);
+ i64 msgid=db_create_message(roomid,data->userid,make_timestamp(),replyid,message);
bool closed=net_send_number(data->fd,tag,msgid);
char *pushbuf=NULL;
char *username=db_get_username(data->userid);
- i64 pushbuflen=asprintf(&pushbuf,"_push message %s %s %" PRIi64 " %" PRIi64 " %s\n",
- roomname,username,timestamp,msgid,message);
+ i64 pushbuflen=asprintf(&pushbuf,
+ "_push message %s %s %" PRIi64 " %" PRIi64 " %" PRIi64 " %s\n",
+ roomname,username,timestamp,msgid,replyid,message);
- event_emit_message(timestamp,message,username,roomname);
+ event_emit_message(timestamp,message,username,roomname,replyid);
firebase_send_message(roomname,roomid,username,message);
free(username);
@@ -317,9 +332,9 @@ static struct cmd_retval history_cmd_helper(
for(i64 i=ml.count-1;i>=0;i--){
char *username=db_get_username(ml.list[i].userid);
- len=asprintf(&buf,"%s history_message %" PRIi64 " %s %s %" PRIi64 " %" PRIi64 " %s\n",
+ len=asprintf(&buf,"%s history_message %" PRIi64 " %s %s %" PRIi64 " %" PRIi64 " %" PRIi64 " %s\n",
tag,ml.count-1-i,roomname,username,ml.list[i].timestamp,
- ml.list[i].msgid,ml.list[i].message);
+ ml.list[i].msgid,ml.list[i].replyid,ml.list[i].message);
free(username);
closed=net_send_raw_text(data->fd,buf,len);
free(buf);
@@ -421,7 +436,7 @@ static const struct cmd_info commands[COMMAND_HASH_MODULUS] = {
COMMAND_ENTRY('l', "list_members", 1, false, cmd_list_members),
COMMAND_ENTRY('c', "create_room", 0, false, cmd_create_room),
COMMAND_ENTRY('i', "invite", 2, false, cmd_invite),
- COMMAND_ENTRY('s', "send", 2, true, cmd_send),
+ 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('p', "ping", 0, false, cmd_ping),
diff --git a/command.h b/command.h
index e1226a5..ebfec8c 100644
--- a/command.h
+++ b/command.h
@@ -4,8 +4,8 @@
#include "conn_data.h"
-#define PROTOCOL_VERSION 1
-#define MIN_SUPPORTED_PROTOCOL_VERSION 1
+#define PROTOCOL_VERSION 2
+#define MIN_SUPPORTED_PROTOCOL_VERSION 2
// Returns true if socket should be closed.
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);
diff --git a/db.h b/db.h
index d1c105b..13df899 100644
--- a/db.h
+++ b/db.h
@@ -16,6 +16,7 @@ struct db_room_list{
struct db_message{
i64 msgid;
i64 roomid,userid,timestamp;
+ i64 replyid; // message this is a reply to, or -1 if normal message
char *message;
};
@@ -59,10 +60,11 @@ struct db_strings_list db_user_tokens(i64 userid);
bool db_add_token(i64 userid,const char *token);
bool db_delete_token(i64 userid,const char *token);
-i64 db_create_message(i64 roomid,i64 userid,i64 timestamp,const char *message); // returns msgid
+i64 db_create_message(i64 roomid,i64 userid,i64 timestamp,i64 replyid,const char *message); // returns msgid
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);
void db_nullify_name_id(struct db_name_id ni);
void db_nullify_room_list(struct db_room_list rl);
diff --git a/event.c b/event.c
index 40eaff8..e85eb45 100644
--- a/event.c
+++ b/event.c
@@ -67,13 +67,14 @@ void event_emit(const struct event_item *event){
}
}
-void event_emit_message(i64 timestamp,const char *message,const char *user,const char *room){
+void event_emit_message(i64 timestamp,const char *message,const char *user,const char *room,i64 replyid){
struct event_item *event=event_item_alloc();
event->type=EVENT_MESSAGE;
event->timestamp=timestamp;
event->message=strdup(message);
event->user=strdup(user);
event->room=strdup(room);
+ event->replyid=replyid;
event_emit(event);
event_item_free(event);
}
diff --git a/event.h b/event.h
index 638cd20..0254702 100644
--- a/event.h
+++ b/event.h
@@ -13,6 +13,7 @@ struct event_item{
enum event_type type;
i64 timestamp; // always set
char *message,*user,*room;
+ i64 replyid;
i64 num;
};
@@ -26,6 +27,6 @@ struct event_item* event_item_alloc(void);
void event_item_free(struct event_item *event);
void event_emit(const struct event_item *event);
-void event_emit_message(i64 timestamp,const char *message,const char *user,const char *room);
+void event_emit_message(i64 timestamp,const char *message,const char *user,const char *room,i64 replyid);
void event_emit_online(i64 timestamp,const char *user,i64 numonline);
void event_emit_join(i64 timestamp,const char *user,const char *room);