aboutsummaryrefslogtreecommitdiff
path: root/weechat
diff options
context:
space:
mode:
Diffstat (limited to 'weechat')
-rw-r--r--weechat/net.c40
-rw-r--r--weechat/net.h6
-rw-r--r--weechat/tomsg.c298
3 files changed, 313 insertions, 31 deletions
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..df6e067 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"
@@ -48,12 +50,100 @@ 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(
+ 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){
@@ -76,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);
@@ -104,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){
@@ -124,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");
@@ -194,6 +292,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 +335,27 @@ 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);
+ }
+
+ // 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){
@@ -327,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;i<conn->nrooms;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;i<conn->nrooms;i++){
close_room(conn->rooms[i]);
}
@@ -462,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;
}
@@ -477,7 +621,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);
}
}
@@ -501,12 +645,15 @@ 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!");
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;
}
@@ -517,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;
@@ -554,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;
@@ -562,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;
@@ -574,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 <hostname> [port]",
- " connect: Connect to a tomsg server",
+ "connect <hostname> [port] | "
+ "reply <msgid> <your 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;
}
@@ -593,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;
}