diff options
-rw-r--r-- | command.c | 31 | ||||
-rw-r--r-- | command.h | 4 | ||||
-rw-r--r-- | db.c | 36 | ||||
-rw-r--r-- | db.h | 4 | ||||
-rw-r--r-- | event.c | 3 | ||||
-rw-r--r-- | event.h | 3 |
6 files changed, 60 insertions, 21 deletions
@@ -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), @@ -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. @@ -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); @@ -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); @@ -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); } @@ -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); |