aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortomsmeding <tom.smeding@gmail.com>2017-03-17 19:57:12 +0100
committertomsmeding <tom.smeding@gmail.com>2017-03-17 19:57:12 +0100
commitadd6b39aece179a0e0ad425af72b8a043a0d3188 (patch)
tree0c64d959587f46d8d43471f9939a1847e32ce02d
parent9a82f91be11a5698c6f0da4dce665e081f3637d0 (diff)
History querying
-rw-r--r--command.c49
-rw-r--r--db.c43
-rw-r--r--db.h2
3 files changed, 93 insertions, 1 deletions
diff --git a/command.c b/command.c
index 50b9534..a691171 100644
--- a/command.c
+++ b/command.c
@@ -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]))
diff --git a/db.c b/db.c
index f89e628..983080f 100644
--- a/db.c
+++ b/db.c
@@ -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;
+}
diff --git a/db.h b/db.h
index f4fea4f..2377ec2 100644
--- a/db.h
+++ b/db.h
@@ -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);