diff options
-rw-r--r-- | command.c | 49 | ||||
-rw-r--r-- | db.c | 43 | ||||
-rw-r--r-- | db.h | 2 |
3 files changed, 93 insertions, 1 deletions
@@ -253,6 +253,54 @@ static bool cmd_send(struct conn_data *data,const char *tag,const char **args){ return closed; } +static bool cmd_history(struct conn_data *data,const char *tag,const char **args){ + char *endp; + i64 nrequested=strtoll(args[1],&endp,10); + if(args[1][0]=='\0'||*endp!='\0'||nrequested<0){ + debug("Connection fd=%d sent an invalid number for 'history': '%s'",data->fd,args[1]); + return true; + } + + if(data->userid==-1){ + send_error(data->fd,tag,"Not logged in"); + return false; + } + i64 roomid=db_find_room(args[0]); + if(roomid==-1){ + send_error(data->fd,tag,"Room not found"); + return false; + } + if(!db_is_member(roomid,data->userid)){ + send_error(data->fd,tag,"Not in that room"); + return false; + } + + struct db_message_list ml=db_get_messages(roomid,nrequested); + char *buf=NULL; + i64 len=asprintf(&buf,"%s history %" PRIi64 "\n",tag,ml.count); + assert(buf); + bool closed=send_raw_text(data->fd,buf,len); + free(buf); + + if(closed){ + db_nullify_message_list(ml); + return true; + } + + for(i64 i=ml.count-1;i>=0;i--){ + char *username=db_get_username(ml.list[i].userid); + len=asprintf(&buf,"%s history_item %" PRIi64 " %s %" PRIi64 " %s\n", + tag,ml.count-1-i,username,ml.list[i].timestamp,ml.list[i].message); + assert(buf); + closed=send_raw_text(data->fd,buf,len); + free(buf); + if(closed)break; + } + + db_nullify_message_list(ml); + return closed; +} + struct cmd_info{ const char *cmdname; @@ -269,6 +317,7 @@ static const struct cmd_info commands[]={ {"create_room",0,false,cmd_create_room}, {"invite",2,false,cmd_invite}, {"send",2,true,cmd_send}, + {"history",2,false,cmd_history}, }; #define NCOMMANDS (sizeof(commands)/sizeof(commands[0])) @@ -244,6 +244,41 @@ void db_create_message(i64 roomid,i64 userid,i64 timestamp,const char *message){ SQLITE(finalize,stmt); } +struct db_message_list db_get_messages(i64 roomid,i64 count){ + sqlite3_stmt *stmt; + SQLITE(prepare_v2,database, + "select user, time, message " + "from Messages " + "where room = ? " + "order by time desc " + "limit ?" + ,-1,&stmt,NULL); + SQLITE(bind_int64,stmt,1,roomid); + SQLITE(bind_int64,stmt,2,count); + + struct db_message_list ml; + i64 cap=count; + ml.count=0; + ml.list=malloc(cap,struct db_message); + + int ret; + while((ret=sqlite3_step(stmt))==SQLITE_ROW){ + if(ml.count==cap){ + die("sqlite gave too many rows while 'limit %" PRIi64 "' was present",count); + } + ml.list[ml.count].roomid=roomid; + ml.list[ml.count].userid=sqlite3_column_int64(stmt,0); + ml.list[ml.count].timestamp=sqlite3_column_int64(stmt,1); + ml.list[ml.count].message=strdup((const char*)sqlite3_column_text(stmt,2)); + ml.count++; + } + + if(ret!=SQLITE_DONE)die_sqlite("sqlite3_step"); + SQLITE(finalize,stmt); + + return ml; +} + void db_nullify_name_id(struct db_name_id ni){ if(ni.name)free(ni.name); @@ -264,3 +299,11 @@ void db_nullify_user_list(struct db_user_list ul){ if(ul.list)free(ul.list); ul.list=NULL; } + +void db_nullify_message_list(struct db_message_list ml){ + for(i64 i=0;i<ml.count;i++){ + free(ml.list[i].message); + } + if(ml.list)free(ml.list); + ml.list=NULL; +} @@ -50,7 +50,7 @@ bool db_delete_user(i64 userid); i64 db_find_user(const char *name); // -1 if not found void db_create_message(i64 roomid,i64 userid,i64 timestamp,const char *message); -struct db_message_list db_get_messages(i64 roomid,i64 timestamp,i64 count); // pass timestamp==-1 for last messages +struct db_message_list db_get_messages(i64 roomid,i64 count); // gets latest `count` messages void db_nullify_name_id(struct db_name_id ni); void db_nullify_room_list(struct db_room_list rl); |