aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--weechat/tomsg.c240
1 files 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 <stdlib.h>
#include <string.h>
#include <sys/socket.h>
+#include <sys/time.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
@@ -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;i<conn->nrooms;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;