aboutsummaryrefslogtreecommitdiff
path: root/command.c
diff options
context:
space:
mode:
Diffstat (limited to 'command.c')
-rw-r--r--command.c95
1 files changed, 71 insertions, 24 deletions
diff --git a/command.c b/command.c
index f69593c..ac6ff09 100644
--- a/command.c
+++ b/command.c
@@ -14,6 +14,7 @@
#include "firebase.h"
#include "user_data.h"
#include "util.h"
+#include "config.h"
#define MAX_MESSAGE_LEN 10000
@@ -309,29 +310,23 @@ static struct cmd_retval cmd_invite(struct conn_data *data,const char *tag,const
return RET_CLOSE(net_send_ok(data->fd,tag));
}
-static struct cmd_retval cmd_send(struct conn_data *data,const char *tag,const char **args){
- if(data->userid==-1){
- net_send_error(data->fd,tag,"Not logged in");
+static struct cmd_retval send_impl(
+ struct conn_data *data,const char *tag,
+ const char *roomname,const char *replyidstr,const char *message,
+ i64 timestamp,bool check_reply_earlier){
+ if(strlen(message)>MAX_MESSAGE_LEN){
+ net_send_error(data->fd,tag,"Message too long");
return RET_OK;
}
- userdata_mark_active(data->userid,data->fd,true);
-
- const char *roomname=args[0];
i64 replyid;
- if(!parse_i64(args[1],&replyid)){
+ if(!parse_i64(replyidstr,&replyid)){
debug("Connection fd=%d sent an invalid number for 'send': '%s'",
- data->fd,args[1]);
+ data->fd,replyidstr);
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;
- }
- i64 roomid=db_find_room(roomname);
+ const i64 roomid=db_find_room(roomname);
if(roomid==-1){
net_send_error(data->fd,tag,"Room not found");
return RET_OK;
@@ -340,21 +335,26 @@ 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){
- struct db_message msg=db_get_message(replyid);
+ const struct db_message msg=db_get_message(replyid);
+ bool error_sent=false;
if(msg.msgid==-1){
net_send_error(data->fd,tag,"Replied-to message not found");
- return RET_OK;
+ error_sent=true;
+ } else if(check_reply_earlier&&msg.timestamp>=timestamp){
+ net_send_error(data->fd,tag,"Replied-to message later than target timestamp");
+ error_sent=true;
}
db_nullify_message(msg);
+ if(error_sent)return RET_OK;
}
- i64 timestamp=make_timestamp();
- i64 msgid=db_create_message(roomid,data->userid,make_timestamp(),replyid,message);
- bool closed=net_send_number(data->fd,tag,msgid);
+ const i64 msgid=db_create_message(roomid,data->userid,timestamp,replyid,message);
+ const bool closed=net_send_number(data->fd,tag,msgid);
char *pushbuf=NULL;
- char *username=db_get_username(data->userid);
+ char *const username=db_get_username(data->userid);
i64 pushbuflen=asprintf(&pushbuf,
"_push message %s %s %" PRIi64 " %" PRIi64 " %" PRIi64 " %s\n",
roomname,username,timestamp,msgid,replyid,message);
@@ -363,7 +363,7 @@ static struct cmd_retval cmd_send(struct conn_data *data,const char *tag,const c
firebase_send_message(roomname,roomid,username,message);
free(username);
- struct db_user_list members=db_list_members(roomid);
+ const struct db_user_list members=db_list_members(roomid);
for(i64 i=0;i<members.count;i++){
i64 nfds;
const int *fds=userdata_online(members.list[i].id,&nfds);
@@ -381,6 +381,52 @@ static struct cmd_retval cmd_send(struct conn_data *data,const char *tag,const c
return RET_CLOSE(closed);
}
+static struct cmd_retval cmd_send(struct conn_data *data, const char *tag, const char **args){
+ if (data->userid == -1) {
+ net_send_error(data->fd, tag, "Not logged in");
+ return RET_OK;
+ }
+ userdata_mark_active(data->userid, data->fd, true);
+
+ const char *roomname = args[0];
+ const char *replyidstr = args[1];
+ const char *message = args[2];
+
+ return send_impl(data, tag, roomname, replyidstr, message, make_timestamp(), false);
+}
+
+static struct cmd_retval cmd_sendat(struct conn_data *data, const char *tag, const char **args){
+ if (data->userid == -1) {
+ net_send_error(data->fd, tag, "Not logged in");
+ return RET_OK;
+ }
+
+ if (data->protversion < 4) {
+ net_send_error(data->fd, tag, "sendat unavailable in protocol version 3");
+ return RET_OK;
+ }
+
+ const char *apikey = args[0];
+ const char *roomname = args[1];
+ const char *replyidstr = args[2];
+ const char *timestampstr = args[3];
+ const char *message = args[4];
+
+ if (!config_check_apikey(apikey).sendat) {
+ net_send_error(data->fd, tag, "sendat not allowed");
+ return RET_OK;
+ }
+
+ i64 timestamp;
+ if (!parse_i64(timestampstr, &timestamp) || timestamp < 0){
+ debug("Connection fd=%d (apikey=%s) sent an invalid timestamp for 'sendat': '%s'",
+ data->fd, apikey, args[2]);
+ return RET_CLOSE(true);
+ }
+
+ return send_impl(data, tag, roomname, replyidstr, message, timestamp, true);
+}
+
static struct cmd_retval history_cmd_helper(
struct conn_data *data,const char *tag,const char **args,
const char *cmdname,i64 beforeid){
@@ -548,8 +594,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, cmd1, len) ((9 * cmd0 + 1 * cmd1 + 3 * len) % COMMAND_HASH_MODULUS)
+#define COMMAND_HASH_MODULUS 32
+#define COMMAND_HASH(cmd0, cmd1, len) ((5 * cmd0 + 9 * cmd1 + 1 * len) % COMMAND_HASH_MODULUS)
#define COMMAND_ENTRY(cmd0, cmd1, cmd, nargs, longlast, handler) \
[COMMAND_HASH(cmd0, cmd1, strlen(cmd))] = {cmd, nargs, longlast, handler}
@@ -568,6 +614,7 @@ static const struct cmd_info commands[COMMAND_HASH_MODULUS] = {
COMMAND_ENTRY('l','e', "leave_room", 1, false, cmd_leave_room),
COMMAND_ENTRY('i','n', "invite", 2, false, cmd_invite),
COMMAND_ENTRY('s','e', "send", 3, true, cmd_send),
+ COMMAND_ENTRY('s','e', "sendat", 5, true, cmd_sendat),
COMMAND_ENTRY('h','i', "history", 2, false, cmd_history),
COMMAND_ENTRY('h','i', "history_before", 3, false, cmd_history_before),
COMMAND_ENTRY('g','e', "get_message", 1, false, cmd_get_message),