From b12ea9fb05e636213b35d46ddaec3e255e1a6992 Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Wed, 29 Jul 2020 22:32:24 +0200 Subject: weechat: Protocol version 2, display replies --- weechat/net.c | 40 +++++++++++++---- weechat/net.h | 6 ++- weechat/tomsg.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 157 insertions(+), 22 deletions(-) (limited to 'weechat') diff --git a/weechat/net.c b/weechat/net.c index 897655a..ce8da6a 100644 --- a/weechat/net.c +++ b/weechat/net.c @@ -220,9 +220,9 @@ void net_handle_recv(int fd,const char *msg){ } const char *roomp=p+1; p=strchr(roomp,' '); - const char *q,*r,*s; + const char *q,*r,*s,*t; if(p==NULL||(q=strchr(p+1,' '))==NULL||(r=strchr(q+1,' '))==NULL - ||(s=strchr(r+1,' '))==NULL){ + ||(s=strchr(r+1,' '))==NULL||(t=strchr(s+1,' '))==NULL){ debugf("net_handle_recv: not enough arguments to 'message' <%s>\n",msg); return; } @@ -233,10 +233,12 @@ void net_handle_recv(int fd,const char *msg){ i64 stamplen=r-stampp; const char *msgidp=r+1; i64 msgidlen=s-msgidp; - const char *textp=s+1; + const char *replyidp=s+1; + i64 replyidlen=t-replyidp; + const char *textp=t+1; i64 textlen=msglen-(textp-msg); - (void)msgidp; (void)msgidlen; + (void)msgidp; (void)msgidlen; (void)replyidlen; struct net_response res; res.type=NET_MESSAGE; @@ -246,6 +248,16 @@ void net_handle_recv(int fd,const char *msg){ debugf("net_handle_recv: timestamp not a number in 'message' <%s>\n",msg); return; } + res.msgid=strtoll(msgidp,(char**)&endp,10); + if(endp-msgidp!=msgidlen){ + debugf("net_handle_recv: msgid not a number in 'message' <%s>\n",msg); + return; + } + res.replyid=strtoll(replyidp,(char**)&endp,10); + if(endp-replyidp!=replyidlen){ + debugf("net_handle_recv: replyid not a number in 'message' <%s>\n",msg); + return; + } res.room=malloc(roomlen+1); res.username=malloc(usernamelen+1); res.message=malloc(textlen+1); @@ -276,9 +288,9 @@ void net_handle_recv(int fd,const char *msg){ } const char *roomp=p+1; p=strchr(roomp,' '); - const char *q,*r,*s; + const char *q,*r,*s,*t; if(p==NULL||(q=strchr(p+1,' '))==NULL||(r=strchr(q+1,' '))==NULL - ||(s=strchr(r+1,' '))==NULL){ + ||(s=strchr(r+1,' '))==NULL||(t=strchr(s+1,' '))==NULL){ debugf("net_handle_recv: not enough arguments to 'history_message' <%s>\n",msg); return; } @@ -289,11 +301,11 @@ void net_handle_recv(int fd,const char *msg){ i64 stamplen=r-stampp; const char *msgidp=r+1; i64 msgidlen=s-msgidp; - const char *textp=s+1; + const char *replyidp=s+1; + i64 replyidlen=t-replyidp; + const char *textp=t+1; i64 textlen=msglen-(textp-msg); - (void)msgidp; (void)msgidlen; - struct net_response res; res.type=NET_HISTORY; const char *endp; @@ -302,6 +314,16 @@ void net_handle_recv(int fd,const char *msg){ debugf("net_handle_recv: timestamp not a number in 'history_message' <%s>\n",msg); return; } + res.msgid=strtoll(msgidp,(char**)&endp,10); + if(endp-msgidp!=msgidlen){ + debugf("net_handle_recv: msgid not a number in 'history_message' <%s>\n",msg); + return; + } + res.replyid=strtoll(replyidp,(char**)&endp,10); + if(endp-replyidp!=replyidlen){ + debugf("net_handle_recv: replyid not a number in 'history_message' <%s>\n",msg); + return; + } res.room=malloc(roomlen+1); res.username=malloc(usernamelen+1); res.message=malloc(textlen+1); diff --git a/weechat/net.h b/weechat/net.h index 63636e7..4a61bca 100644 --- a/weechat/net.h +++ b/weechat/net.h @@ -17,8 +17,8 @@ enum net_response_type{ NET_NAME, // name NET_LIST, // nitems, items NET_PONG, // - - NET_MESSAGE, // room, username, timestamp, message - NET_HISTORY, // room, username, timestamp, message + NET_MESSAGE, // room, username, timestamp, msgid, replyid, message + NET_HISTORY, // room, username, timestamp, msgid, replyid, message NET_JOIN, // room, username NET_INVITE, // room, username NET_ONLINE, // online.username, online.num @@ -38,6 +38,8 @@ struct net_response{ char *room; char *username; i64 timestamp; + i64 msgid; + i64 replyid; char *message; }; struct { diff --git a/weechat/tomsg.c b/weechat/tomsg.c index 04213ae..e008104 100644 --- a/weechat/tomsg.c +++ b/weechat/tomsg.c @@ -21,6 +21,8 @@ WEECHAT_PLUGIN_PRIORITY(1000) static const char *errpfx,*netpfx; +#define PROTOCOL_VERSION 2 + #define NICK_COLOR "default" #define NICK_AWAY_COLOR "weechat.color.nicklist_away" @@ -56,6 +58,86 @@ static struct t_weechat_plugin *weechat_plugin; static struct t_hashtable *conntable; +static void display_message( + struct roomdata *room, + int64_t timestamp, + const char *username, + const char *message, + int64_t msgid, + bool is_reply +) { + char tags[128]; + int pos = snprintf(tags, sizeof tags, "tomsgid_%" PRIi64, msgid); + strcpy(tags + pos, room->nmembers <= 2 ? ",notify_private" : ",notify_message"); + if (is_reply) { + strcat(tags, ",tomsg_reply"); + } + + weechat_printf_date_tags( + room->buffer, timestamp / 1000000LL, + tags, + "%s\t%s", username, message + ); +} + +static void edit_reply_message( + struct roomdata *room, + int64_t msgid, + const char *new_message +) { + struct t_hdata *buffer_h = weechat_hdata_get("buffer"); + struct t_hdata *lines_h = weechat_hdata_get("lines"); + struct t_hdata *line_h = weechat_hdata_get("line"); + struct t_hdata *line_data_h = weechat_hdata_get("line_data"); + + struct t_gui_lines *lines_ptr = weechat_hdata_pointer(buffer_h, room->buffer, "lines"); + if (!lines_ptr) { + debugf("ERROR: Cannot get lines_ptr!"); + return; + } + + struct t_gui_line *line_ptr = weechat_hdata_pointer(lines_h, lines_ptr, "last_line"); + struct t_gui_line_data *line_data_ptr; + + while (line_ptr) { + line_data_ptr = weechat_hdata_pointer(line_h, line_ptr, "data"); + + const int tags_count = weechat_hdata_integer(line_data_h, line_data_ptr, "tags_count"); + bool have_reply_tag = false; + bool have_msgid_tag = false; + for (int i = 0; i < tags_count; i++) { + char key[32]; + snprintf(key, sizeof key, "%d|tags_array", i); + const char *tag = weechat_hdata_string(line_data_h, line_data_ptr, key); + if (strcmp(tag, "tomsg_reply") == 0) { + have_reply_tag = true; + } else if (memcmp(tag, "tomsgid_", 8) == 0) { + int64_t this_id = strtoll(tag + 8, NULL, 10); + if (this_id == msgid) have_msgid_tag = true; + } + } + + if (have_reply_tag && have_msgid_tag) break; + + line_ptr = weechat_hdata_pointer(line_h, line_ptr, "prev_line"); + } + + if (line_ptr) { + debugf("edit_reply_message: found line\n"); + struct t_hashtable *hashtable = + weechat_hashtable_new( + 8, WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_STRING, NULL, NULL); + if (hashtable) { + weechat_hashtable_set(hashtable, "message", new_message); + weechat_hdata_update(line_data_h, line_data_ptr, hashtable); + weechat_hashtable_free(hashtable); + } + } else { + debugf("edit_reply_message: not found!\n"); + } +} + + static void room_update_attributes(struct roomdata *room){ bool private=room->nmembers<=2; weechat_buffer_set(room->buffer,"localvar_set_type",private?"private":"channel"); @@ -194,6 +276,28 @@ static void members_net_callback(int fd,struct net_response res,void *payload){ room_update_attributes(room); } +struct room_and_msgid { + struct roomdata *room; + int64_t msgid; +}; + +static void reply_get_message_net_callback(int fd, struct net_response res, void *payload) { + (void)fd; + struct room_and_msgid *data = (struct room_and_msgid*)payload; + + debugf("Got reply from get_message for msgid=%" PRIi64 "\n", res.msgid); + + const char *green = weechat_color("green"); + + size_t prefixlen = strlen(green) + 3 + strlen(res.username) + 2; + char *buffer = malloc(prefixlen + strlen(res.message) + 1); + sprintf(buffer, "%s> <%s> %s", weechat_color("green"), res.username, res.message); + edit_reply_message(data->room, data->msgid, buffer); + free(buffer); + + free(data); +} + static void push_net_callback(int fd,struct net_response res,void *payload){ (void)payload; debugf("push_net_callback(fd=%d,res={.type=%d})\n",fd,res.type); @@ -215,15 +319,22 @@ static void push_net_callback(int fd,struct net_response res,void *payload){ create_room_buffer(room); } - if(res.type==NET_MESSAGE){ - bool private=room->nmembers<=2; - weechat_printf_date_tags( - room->buffer,res.timestamp/1000000LL,private?"notify_private":"notify_message", - "%s\t%s",res.username,res.message); - } else if(res.type==NET_HISTORY){ - weechat_printf_date_tags( - room->buffer,res.timestamp/1000000LL,NULL, - "%s\t%s",res.username,res.message); + if(res.type==NET_MESSAGE||res.type==NET_HISTORY){ + if(res.replyid!=-1){ + debugf("Found reply msgid=%" PRIi64 " replyid=%" PRIi64 "\n",res.msgid,res.replyid); + char str[128]; + snprintf(str,sizeof str,"%s> ...",weechat_color("green")); + display_message(room,res.timestamp,res.username,str,res.msgid,true); + display_message(room,res.timestamp,"",res.message,res.msgid,false); + + struct room_and_msgid *payload=malloc(sizeof(struct room_and_msgid)); + assert(payload); + payload->room=room; + payload->msgid=res.msgid; + net_sendf(fd,reply_get_message_net_callback,payload,"get_message %" PRIi64,res.replyid); + } else { + display_message(room,res.timestamp,res.username,res.message,res.msgid,false); + } } else if(res.type==NET_JOIN){ weechat_printf(room->buffer,"%sUser %s joined this room",netpfx,res.username); if(room->buffer_nickgroup){ @@ -477,7 +588,7 @@ static void version_net_callback(int fd,struct net_response res,void *payload){ weechat_printf(conn->buffer,"Version negotiation complete."); } else { conn_destroy(conn); - weechat_printf(NULL,"tomsg: Server has incompatible protocol version (we want 1)!"); + weechat_printf(NULL,"tomsg: Server has incompatible protocol version (we want %d)!",PROTOCOL_VERSION); } } @@ -506,7 +617,7 @@ static int connect_cb(const void *_p,void *hostname,int status,int _g,int fd,con weechat_hashtable_set(conntable,&fd,conn); - net_sendf(fd,version_net_callback,NULL,"version 1"); + net_sendf(fd,version_net_callback,NULL,"version %d", PROTOCOL_VERSION); return WEECHAT_RC_OK; } -- cgit v1.2.3-70-g09d2 From 79c8ffd915115728070339f30d57a3a3e31bd322 Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Thu, 30 Jul 2020 20:43:25 +0200 Subject: weechat: WIP replies and protocol version 2, is at least compatible --- weechat/tomsg.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 156 insertions(+), 9 deletions(-) (limited to 'weechat') diff --git a/weechat/tomsg.c b/weechat/tomsg.c index e008104..df6e067 100644 --- a/weechat/tomsg.c +++ b/weechat/tomsg.c @@ -50,12 +50,20 @@ struct conndata{ i64 linebuf_sz,linebuf_len; char *linebuf; + + // struct t_hashtable *msgtable; // msgid -> msgdata }; +// struct msgdata{ +// char *username; +// char *message; +// }; + static struct t_weechat_plugin *weechat_plugin; -static struct t_hashtable *conntable; +static struct t_hashtable *conntable; // fd -> conndata +static struct t_hashtable *roomtable; // roomname -> roomdata static void display_message( @@ -158,7 +166,7 @@ static void close_room(struct roomdata *room){ } static void message_net_callback(int fd,struct net_response res,void *payload){ - (void)payload; + // struct msgdata *msgdata=(struct msgdata*)payload; debugf("message_net_callback(fd=%d,res={.type=%d})\n",fd,res.type); struct conndata *conn=weechat_hashtable_get(conntable,&fd); assert(conn); @@ -186,7 +194,12 @@ static int room_input_cb(const void *room_vp,void *_d,struct t_gui_buffer *buffe tosend=input+skipfirst; } - net_sendf(conn->fd,message_net_callback,NULL,"send %s %s",room->name,tosend); + // struct msgdata *msgdata=malloc(sizeof(msgdata)); + // msgdata->username=strdup(conn->username); + // msgdata->message=strdup(tosend); + void *msgdata=NULL; + + net_sendf(conn->fd,message_net_callback,msgdata,"send %s -1 %s",room->name,tosend); weechat_printf(room->buffer,"%s\t%s",conn->username,tosend); if(free_tosend){ @@ -206,6 +219,9 @@ static void create_room_buffer(struct roomdata *room){ if(room->buffer!=NULL){ weechat_buffer_close(room->buffer); } + + weechat_hashtable_set(roomtable,room->name,room); + room->buffer= weechat_buffer_new(room->name, room_input_cb,room,NULL, room_close_cb,room,NULL); weechat_buffer_set(room->buffer,"nicklist","1"); @@ -335,6 +351,11 @@ static void push_net_callback(int fd,struct net_response res,void *payload){ } else { display_message(room,res.timestamp,res.username,res.message,res.msgid,false); } + + // struct msgdata *msgdata=malloc(sizeof(msgdata)); + // msgdata->username=strdup(res.username); + // msgdata->message=strdup(res.message); + // weechat_hashtable_set(conn->msgtable,(void*)res.msgid,msgdata); } else if(res.type==NET_JOIN){ weechat_printf(room->buffer,"%sUser %s joined this room",netpfx,res.username); if(room->buffer_nickgroup){ @@ -438,7 +459,17 @@ static void pong_net_callback(int fd,struct net_response res,void *payload){ static void conn_destroy(struct conndata *conn){ debugf("conn_destroy(conn=%p (fd=%d))\n",conn,conn->fd); weechat_unhook(conn->fd_hook); + if(conntable)weechat_hashtable_remove(conntable,&conn->fd); + if(roomtable){ + for(int i=0;inrooms;i++){ + weechat_hashtable_remove(roomtable,conn->rooms[i]->name); + } + } + + // TODO: free all items in the hashtable + // weechat_hashtable_free(conn->msgtable); + for(int i=0;inrooms;i++){ close_room(conn->rooms[i]); } @@ -573,8 +604,10 @@ static char* password_hide_modifier(const void *_p,void *_d,const char *modifier static int conn_close_cb(const void *conn_vp,void *_d,struct t_gui_buffer *buffer){ (void)_d; (void)buffer; struct conndata *conn=(struct conndata*)conn_vp; - debugf("conn_close_cb(conn=%p,buffer=%p) fd=%d\n",conn,buffer,conn->fd); - conn_destroy(conn); + if(conn){ + debugf("conn_close_cb(conn=%p,buffer=%p) fd=%d\n",conn,buffer,conn->fd); + conn_destroy(conn); + } return WEECHAT_RC_OK; } @@ -612,6 +645,9 @@ static int connect_cb(const void *_p,void *hostname,int status,int _g,int fd,con conn->linebuf_len=0; conn->linebuf=malloc(conn->linebuf_sz); assert(conn->linebuf); + // conn->msgtable=weechat_hashtable_new( + // 4096, WEECHAT_HASHTABLE_INTEGER, WEECHAT_HASHTABLE_POINTER, NULL, NULL); + // assert(conn->msgtable); weechat_printf(conn->buffer,"Connected!"); @@ -628,8 +664,10 @@ static int connect_cb(const void *_p,void *hostname,int status,int _g,int fd,con } } -static int cmd_tomsg_cb(const void *_p,void *_d,struct t_gui_buffer *buffer,int argc,char **argv,char **_a){ - (void)_p; (void)_d; (void)_a; +static int cmd_tomsg_cb( + const void *_p,void *_d,struct t_gui_buffer *buffer, + int argc,char **argv,char **argv_eol){ + (void)_p; (void)_d; if(argc<2){ weechat_printf(buffer,"%stomsg: Invalid number of arguments to /tomsg",errpfx); return WEECHAT_RC_ERROR; @@ -665,6 +703,50 @@ static int cmd_tomsg_cb(const void *_p,void *_d,struct t_gui_buffer *buffer,int NULL,NULL,0,NULL, NULL, connect_cb,NULL,hostname_copy); + } else if(strcmp(argv[1],"reply")==0){ + if(argc<4){ + weechat_printf(buffer,"%stomsg: Invalid number of arguments to /tomsg reply",errpfx); + return WEECHAT_RC_ERROR; + } + + char *endp; + int64_t msgid=strtol(argv[2],&endp,10); + if(*argv[2]=='\0'||*endp!='\0'){ + weechat_printf(NULL,"%stomsg: Invalid msgid argument to /tomsg reply",errpfx); + return WEECHAT_RC_ERROR; + } + + const char *buffername=weechat_buffer_get_string(buffer,"full_name"); + debugf("tomsg reply: buffername=<%s>\n",buffername); + const char *prefix="tomsg."; + size_t prefixlen=strlen(prefix); + if(strlen(buffername)>prefixlen&& + memcmp(buffername,prefix,prefixlen)==0){ + struct roomdata *room= + weechat_hashtable_get(roomtable,buffername+prefixlen); + if(!room){ + weechat_printf(NULL,"%stomsg: Cannot locate internal room data!",errpfx); + return WEECHAT_RC_ERROR; + } + + const char *message_body=argv_eol[3]; + + // struct msgdata *msgdata=malloc(sizeof(struct msgdata)); + // msgdata->username=strdup(room->conn->username); + // msgdata->message=strdup(message_body); + void *msgdata=NULL; + + int fd=room->conn->fd; + net_sendf(fd,message_net_callback,msgdata,"send %s %" PRIi64 " %s",room->name,msgid,message_body); + + // TODO: fix this + weechat_printf(room->buffer,"%s\t%s> ...", + room->conn->username,weechat_color("green")); + weechat_printf(room->buffer,"\t%s",message_body); + } else { + weechat_printf(NULL,"%stomsg: /tomsg reply on a non-tomsg buffer",errpfx); + return WEECHAT_RC_ERROR; + } } else { weechat_printf(buffer,"%stomsg: Unknown command \"%s\" to /tomsg",errpfx,argv[1]); return WEECHAT_RC_ERROR; @@ -673,6 +755,62 @@ static int cmd_tomsg_cb(const void *_p,void *_d,struct t_gui_buffer *buffer,int return WEECHAT_RC_OK; } +static void bind_key_easy(const char *context, const char *key, const char *value) { + struct t_hashtable *ht = weechat_hashtable_new( + 1, WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_STRING, NULL, NULL); + weechat_hashtable_set(ht, key, value); + weechat_key_bind(context, ht); + weechat_hashtable_free(ht); +} + +static int cursor_reply_signal_cb( + const void *pointer_, void *data_, + const char *signal, struct t_hashtable *hashtable +) { + (void)pointer_; (void)data_; (void)signal; + + const char *tags = weechat_hashtable_get(hashtable, "_chat_line_tags"); + weechat_command(NULL, "/cursor stop"); + + int64_t msgid = -1; + while (*tags) { + const char *ptr = strchr(tags, ','); + if (ptr - tags > (ptrdiff_t)strlen("tomsgid_")) { + char *endp; + msgid = strtoll(tags + 8, &endp, 10); + if ((ptr == NULL && *endp == '\0') || endp == ptr) { + break; + } + msgid = -1; + } + } + + if (msgid == -1) return WEECHAT_RC_OK; + + const char *buffer_name = weechat_hashtable_get(hashtable, "_buffer_full_name"); + struct t_gui_buffer *bufptr = weechat_buffer_search("==", buffer_name); + + const char *current_input = weechat_buffer_get_string(bufptr, "input"); + int input_pos = weechat_buffer_get_integer(bufptr, "input_pos"); + + size_t new_input_capacity = 64 + strlen(current_input) + 1; + char *new_input = malloc(new_input_capacity); + assert(new_input); + int total_length = snprintf( + new_input, new_input_capacity, "/tomsg reply %" PRIi64 " %s", + msgid, current_input); + int prefix_length = total_length - strlen(current_input); + + weechat_buffer_set(bufptr, "input", new_input); + free(new_input); + + char posbuf[64]; + snprintf(posbuf, sizeof posbuf, "%d", prefix_length + input_pos); + weechat_buffer_set(bufptr, "input_pos", posbuf); + + return WEECHAT_RC_OK; +} + int weechat_plugin_init(struct t_weechat_plugin *plugin,int argc,char **argv){ (void)argc; (void)argv; weechat_plugin = plugin; @@ -685,18 +823,25 @@ int weechat_plugin_init(struct t_weechat_plugin *plugin,int argc,char **argv){ weechat_hook_command( "tomsg", "Execute commands related to tomsg.", - "connect [port]", - " connect: Connect to a tomsg server", + "connect [port] | " + "reply ", + " connect: Connect to a tomsg server\n" + " reply: Reply to a message in a tomsg buffer. Tip: use middleclick-R.", NULL, cmd_tomsg_cb,NULL,NULL); weechat_hook_modifier("input_text_display_with_cursor",password_hide_modifier,NULL,NULL); + weechat_hook_hsignal("tomsg_cursor_reply", cursor_reply_signal_cb, NULL, NULL); + bind_key_easy("cursor","@chat(tomsg.*):r","hsignal:tomsg_cursor_reply"); + net_set_push_callback(push_net_callback); net_set_history_callback(history_push_net_callback); conntable=weechat_hashtable_new( 16,WEECHAT_HASHTABLE_INTEGER,WEECHAT_HASHTABLE_POINTER,NULL,NULL); + roomtable=weechat_hashtable_new( + 16,WEECHAT_HASHTABLE_STRING,WEECHAT_HASHTABLE_POINTER,NULL,NULL); return WEECHAT_RC_OK; } @@ -704,7 +849,9 @@ int weechat_plugin_init(struct t_weechat_plugin *plugin,int argc,char **argv){ int weechat_plugin_end(struct t_weechat_plugin *plugin){ (void)plugin; weechat_hashtable_free(conntable); + weechat_hashtable_free(roomtable); conntable=NULL; + roomtable=NULL; debug_deinit(); return WEECHAT_RC_OK; } -- cgit v1.2.3-70-g09d2