diff options
Diffstat (limited to 'command.c')
-rw-r--r-- | command.c | 95 |
1 files changed, 71 insertions, 24 deletions
@@ -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, ×tamp) || 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), |