From 73a76cc9e51f9433e7540df454bc95e0e82357bf Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Sat, 8 Aug 2020 20:38:55 +0200 Subject: weechat: Fixup msgid in tags of own messages --- weechat/tomsg.c | 240 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 179 insertions(+), 61 deletions(-) diff --git a/weechat/tomsg.c b/weechat/tomsg.c index df6e067..bd01165 100644 --- a/weechat/tomsg.c +++ b/weechat/tomsg.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,7 @@ struct roomdata{ struct t_gui_buffer *buffer; struct t_gui_nick_group *buffer_nickgroup; int nmembers; + int next_pending_id; struct conndata *conn; // do not free }; @@ -50,15 +52,8 @@ 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; @@ -66,20 +61,27 @@ static struct t_hashtable *conntable; // fd -> conndata static struct t_hashtable *roomtable; // roomname -> roomdata +static i64 gettimestamp(void) { + struct timeval tv; + gettimeofday(&tv,NULL); + return (i64)tv.tv_sec*1000000+tv.tv_usec; +} + + static void display_message( struct roomdata *room, int64_t timestamp, const char *username, const char *message, int64_t msgid, - bool is_reply + bool is_reply, + bool is_history ) { 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"); - } + snprintf(tags, sizeof tags, "tomsgid_%" PRIi64 "%s%s", + msgid, + room->nmembers == 2 && !is_history ? ",notify_private" : ",notify_message", + is_reply ? ",tomsg_reply" : ""); weechat_printf_date_tags( room->buffer, timestamp / 1000000LL, @@ -88,11 +90,7 @@ static void display_message( ); } -static void edit_reply_message( - struct roomdata *room, - int64_t msgid, - const char *new_message -) { +static struct t_gui_line_data* find_hdata_line_data_ptr(struct roomdata *room, int64_t msgid, bool must_be_reply) { 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"); @@ -101,7 +99,7 @@ static void edit_reply_message( struct t_gui_lines *lines_ptr = weechat_hdata_pointer(buffer_h, room->buffer, "lines"); if (!lines_ptr) { debugf("ERROR: Cannot get lines_ptr!"); - return; + return NULL; } struct t_gui_line *line_ptr = weechat_hdata_pointer(lines_h, lines_ptr, "last_line"); @@ -125,12 +123,56 @@ static void edit_reply_message( } } - if (have_reply_tag && have_msgid_tag) break; + if ((have_reply_tag || !must_be_reply) && have_msgid_tag) break; line_ptr = weechat_hdata_pointer(line_h, line_ptr, "prev_line"); } - if (line_ptr) { + if (line_ptr) return line_data_ptr; + else return NULL; +} + +static char *collect_line_data_tags(struct t_gui_line_data *line_data_ptr) { + struct t_hdata *line_data_h = weechat_hdata_get("line_data"); + + const int tags_count = weechat_hdata_integer(line_data_h, line_data_ptr, "tags_count"); + + size_t buffer_cap = 256, buffer_len = 0; + char *buffer = malloc(buffer_cap); + assert(buffer); + + 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); + const size_t len = strlen(tag); + + // "+ 1" for the comma, "- 1" for the final null byte + if (buffer_len + 1 + len >= buffer_cap - 1) { + do buffer_cap *= 2; + while (buffer_len + 1 + len >= buffer_cap - 1); + buffer = realloc(buffer, buffer_cap); + assert(buffer); + } + + if (i > 0) buffer[buffer_len++] = ','; + memcpy(buffer + buffer_len, tag, len); + buffer_len += len; + } + + buffer[buffer_len] = '\0'; + return buffer; +} + +static void edit_reply_message( + struct roomdata *room, + int64_t msgid, + const char *new_message +) { + struct t_hdata *line_data_h = weechat_hdata_get("line_data"); + struct t_gui_line_data *line_data_ptr = find_hdata_line_data_ptr(room, msgid, true); + + if (line_data_ptr) { debugf("edit_reply_message: found line\n"); struct t_hashtable *hashtable = weechat_hashtable_new( @@ -145,9 +187,72 @@ static void edit_reply_message( } } +static void edit_message_msgid(struct roomdata *room, int64_t pending_id, int64_t new_msgid) { + debugf("edit_message_msgid: looking for %" PRIi64 ", replacing with %" PRIi64 "\n", pending_id, new_msgid); + + struct t_hdata *const line_data_h = weechat_hdata_get("line_data"); + struct t_gui_line_data *const line_data_ptr = find_hdata_line_data_ptr(room, pending_id, false); + + if (!line_data_ptr) { + debugf("edit_message_msgid: not found!\n"); + return; + } + + debugf("edit_message_msgid: found line\n"); + + char *const tags_str = collect_line_data_tags(line_data_ptr); + const size_t tags_len = strlen(tags_str); + + size_t cursor = 0; + char *endptr; + size_t taglen = 0; + while (cursor < tags_len) { + endptr = strchr(tags_str + cursor, ','); + taglen = endptr == NULL + ? tags_len - cursor + : (size_t)(endptr - (tags_str + cursor)); + + if (memcmp(tags_str + cursor, "tomsgid_", 8) == 0) { + int64_t this_id = strtoll(tags_str + cursor + 8, NULL, 10); + if (this_id == pending_id) break; + } + + cursor += taglen + 1; + } + + if (cursor >= tags_len) { + debugf("edit_message_msgid: msgid not found in tags?\n"); + return; + } + + // Splice the pending tag out + tags_str[cursor] = '\0'; + char *tags_before = tags_str; + char *tags_after = endptr; + + // Add the new tag at the end + char *new_tags_str = NULL; + asprintf(&new_tags_str, "%stomsgid_%" PRIi64 "%s", tags_before, new_msgid, tags_after); + assert(new_tags_str); + + free(tags_str); + + // Persist the new tags array + struct t_hashtable *hashtable = + weechat_hashtable_new( + 8, WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_STRING, NULL, NULL); + if (hashtable) { + weechat_hashtable_set(hashtable, "tags_array", new_tags_str); + weechat_hdata_update(line_data_h, line_data_ptr, hashtable); + weechat_hashtable_free(hashtable); + } + + free(new_tags_str); +} + static void room_update_attributes(struct roomdata *room){ - bool private=room->nmembers<=2; + bool private=room->nmembers==2; weechat_buffer_set(room->buffer,"localvar_set_type",private?"private":"channel"); weechat_buffer_set(room->buffer,"notify",private?"3":"1"); debugf("room_update_attributes: set private for room %s to %d\n",room->name,private); @@ -165,14 +270,25 @@ static void close_room(struct roomdata *room){ free(room); } +struct pending_ids { + struct roomdata *room; + int num; // must be <=2 + i64 ids[2]; +}; + static void message_net_callback(int fd,struct net_response res,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); - if(res.type==NET_ERROR){ - weechat_printf(conn->buffer,"tomsg: send threw error: %s",res.error); - } else if(res.type!=NET_NUMBER){ + struct pending_ids *pending_ids = (struct pending_ids*)payload; + debugf("message_net_callback(fd=%d,res={.type=%d})\n", fd, res.type); + + if (res.type == NET_ERROR) { + struct conndata *conn = weechat_hashtable_get(conntable, &fd); + assert(conn); + weechat_printf(conn->buffer, "tomsg: send threw error: %s", res.error); + } else if (res.type == NET_NUMBER) { + for (int i = 0; i < pending_ids->num; i++) { + edit_message_msgid(pending_ids->room, -pending_ids->ids[i], res.number); + } + } else { debugf("message_net_callback: res.type=%d\n",res.type); } } @@ -194,13 +310,13 @@ static int room_input_cb(const void *room_vp,void *_d,struct t_gui_buffer *buffe tosend=input+skipfirst; } - // 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); + struct pending_ids *payload=malloc(sizeof(struct pending_ids)); + assert(payload); + payload->room=room; + payload->num=1; + payload->ids[0]=room->next_pending_id++; + net_sendf(conn->fd,message_net_callback,payload,"send %s -1 %s",room->name,tosend); + display_message(room,gettimestamp(),conn->username,tosend,-payload->ids[0],false,false); if(free_tosend){ free((void*)tosend); @@ -340,8 +456,8 @@ static void push_net_callback(int fd,struct net_response res,void *payload){ 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); + display_message(room,res.timestamp,res.username,str,res.msgid,true,res.type==NET_HISTORY); + display_message(room,res.timestamp,"",res.message,res.msgid,false,res.type==NET_HISTORY); struct room_and_msgid *payload=malloc(sizeof(struct room_and_msgid)); assert(payload); @@ -349,13 +465,8 @@ static void push_net_callback(int fd,struct net_response res,void *payload){ 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); + display_message(room,res.timestamp,res.username,res.message,res.msgid,false,res.type==NET_HISTORY); } - - // 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){ @@ -416,6 +527,9 @@ static void roomlist_net_callback(int fd,struct net_response res,void *payload){ room->name=strdup(res.items[i]); room->conn=conn; room->buffer=NULL; + room->buffer_nickgroup=NULL; + room->nmembers=0; + room->next_pending_id=1; create_room_buffer(room); net_sendf(fd,history_net_callback,room,"history %s 10",room->name); net_sendf(fd,members_net_callback,room,"list_members %s",room->name); @@ -467,9 +581,6 @@ static void conn_destroy(struct conndata *conn){ } } - // TODO: free all items in the hashtable - // weechat_hashtable_free(conn->msgtable); - for(int i=0;inrooms;i++){ close_room(conn->rooms[i]); } @@ -531,7 +642,7 @@ static int conn_input_cb(const void *conn_vp,void *_d,struct t_gui_buffer *buffe weechat_printf(conn->buffer,"Server protocol version not yet negotiated, please wait..."); return WEECHAT_RC_OK; } - + char *input2=strdup(input); assert(input2); char *cursor=input2; @@ -645,9 +756,6 @@ 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!"); @@ -731,18 +839,28 @@ static int cmd_tomsg_cb( 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; + struct pending_ids *msg_payload=malloc(sizeof(struct pending_ids)); + assert(msg_payload); + msg_payload->room=room; + msg_payload->num=2; + msg_payload->ids[0]=room->next_pending_id++; + msg_payload->ids[1]=room->next_pending_id++; 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); + net_sendf(fd,message_net_callback,msg_payload,"send %s %" PRIi64 " %s",room->name,msgid,message_body); + + char str[128]; + snprintf(str,sizeof str,"%s> ...",weechat_color("green")); + i64 timestamp=gettimestamp(); + display_message(room,timestamp,room->conn->username,str,-msg_payload->ids[0],true,false); + display_message(room,timestamp,"",message_body,-msg_payload->ids[1],false,false); + + // TODO: do get_payload in message_net_callback + // struct room_and_msgid *get_payload=malloc(sizeof(struct room_and_msgid)); + // assert(get_payload); + // get_payload->room=room; + // get_payload->msgid=msgid; + // net_sendf(fd,reply_get_message_net_callback,get_payload,"get_message %" PRIi64,msgid); } else { weechat_printf(NULL,"%stomsg: /tomsg reply on a non-tomsg buffer",errpfx); return WEECHAT_RC_ERROR; -- cgit v1.2.3-70-g09d2