From 2b86c851562f86f69acbf4b773107077680d5068 Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Fri, 7 Apr 2017 23:59:03 +0200 Subject: Push weechat plugin --- weechat/net.c | 291 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 weechat/net.c (limited to 'weechat/net.c') diff --git a/weechat/net.c b/weechat/net.c new file mode 100644 index 0000000..12e3625 --- /dev/null +++ b/weechat/net.c @@ -0,0 +1,291 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include "net.h" + + +extern FILE *debugf; + + +struct store_item{ + char *id; + net_callback_t *cb; + void *payload; +}; + +static i64 store_cap=16,store_len=0; +static struct store_item *store=NULL; + +static net_callback_t *push_callback=NULL; +static net_callback_t *history_callback=NULL; + + +#define ALPHABET "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +static void uniqid8(char *dst){ + static i64 static_id=0; + static const int alphabet_len=strlen(ALPHABET); + + int id=static_id; + static_id++; + for(int i=7;i>=0;i--){ + dst[i]=ALPHABET[id%alphabet_len]; + id/=alphabet_len; + } +} + +void net_set_push_callback(net_callback_t *callback){ + push_callback=callback; +} + +void net_set_history_callback(net_callback_t *callback){ + history_callback=callback; +} + +__attribute__((format (printf, 4, 5))) +bool net_sendf(int fd,net_callback_t *callback,void *payload,const char *format,...){ + if(store==NULL){ + store=malloc(store_cap*sizeof(struct store_item)); + } else if(store_len==store_cap){ + store_cap*=2; + store=realloc(store,store_cap*sizeof(struct store_item)); + } + assert(store); + + fprintf(debugf,"net_sendf(%d,%p,\"%s\",...)\n",fd,callback,format); + + va_list ap,ap2; + va_start(ap,format); + va_copy(ap2,ap); + i64 len=vsnprintf(NULL,0,format,ap2); + va_end(ap2); + assert(len>=0); + + char *buf=malloc(9+len+2); + assert(buf); + uniqid8(buf); + buf[8]=' '; + i64 len2=vsprintf(buf+9,format,ap); + va_end(ap); + assert(len2==len); + buf[9+len]='\n'; + buf[9+len+1]='\0'; + + store[store_len].id=malloc(9); + assert(store[store_len].id); + memcpy(store[store_len].id,buf,8); + store[store_len].id[8]='\0'; + store[store_len].cb=callback; + store[store_len].payload=payload; + store_len++; + + i64 cursor=0,total=9+len+1; + while(cursor\n",msg); + return; + } + i64 taglen=p-msg; + + net_callback_t *cb=NULL; + void *payload=NULL; + if(taglen==5&&memcmp(msg,"_push",5)==0){ + cb=push_callback; + } else if(*p!='\0'&&memcmp(p+1,"history_message",15)==0){ + cb=history_callback; + } else { + if(taglen!=8){ + fprintf(debugf,"net_handle_recv: tag not length 8 <%s>\n",msg); + return; + } + for(i64 i=0;i\n",msg); + return; + } + } + + const char *cmd=p+1; + p=strchr(cmd,' '); + if(p==NULL)p=msg+msglen; + i64 cmdlen=p-cmd; + + // Now `p` points to the space (or '\0') after the command name + + if(cmdlen==2&&memcmp(cmd,"ok",2)==0){ + cb(fd,(struct net_response){.type=NET_OK},payload); + } else if(cmdlen==5&&memcmp(cmd,"error",5)==0){ + struct net_response res=(struct net_response){ + .type=NET_ERROR, + .error=strdup(*p=='\0'?p:p+1) + }; + cb(fd,res,payload); + free(res.error); + } else if(cmdlen==4&&memcmp(cmd,"name",4)==0){ + struct net_response res=(struct net_response){ + .type=NET_NAME, + .name=strdup(*p=='\0'?p:p+1) + }; + cb(fd,res,payload); + free(res.name); + } else if(cmdlen==4&&memcmp(cmd,"list",4)==0){ + struct net_response res=(struct net_response){.type=NET_LIST}; + if(*p=='\0'){ + fprintf(debugf,"net_handle_recv: no list count <%s>\n",msg); + return; + } + const char *cursor=p+1; + p=strchr(cursor,' '); + res.nitems=strtol(cursor,NULL,10); + if(res.nitems<=0){ + fprintf(debugf,"net_handle_recv: -- 0 items <%s>\n",msg); + res.nitems=0; + res.items=NULL; + cb(fd,res,payload); + return; + } + res.items=malloc(res.nitems*sizeof(char*)); + assert(res.items); + cursor=p; + for(i64 i=0;i\n",msg); + return; + } + cursor++; + p=strchr(cursor,' '); + if(p==NULL)p=msg+msglen; + res.items[i]=malloc(p-cursor+1); + assert(res.items[i]); + memcpy(res.items[i],cursor,p-cursor); + res.items[i][p-cursor]='\0'; + fprintf(debugf,"net_handle_recv: -- item \"%s\" <%s>\n",res.items[i],msg); + cursor=p; + } + cb(fd,res,payload); + for(i64 i=0;i\n",msg); + return; + } + const char *roomp=p+1; + p=strchr(roomp,' '); + const char *q,*r; + if(p==NULL||(q=strchr(p+1,' '))==NULL||(r=strchr(q+1,' '))==NULL){ + fprintf(debugf,"net_handle_recv: not enough arguments to 'message' <%s>\n",msg); + return; + } + i64 roomlen=p-roomp; + const char *usernamep=p+1; + i64 usernamelen=q-usernamep; + const char *stampp=q+1; + i64 stamplen=r-stampp; + const char *textp=r+1; + i64 textlen=msglen-(textp-msg); + + struct net_response res; + res.type=NET_MESSAGE; + const char *endp; + res.timestamp=strtoll(stampp,(char**)&endp,10); + if(endp-stampp!=stamplen){ + fprintf(debugf,"net_handle_recv: timestamp not a number in 'message' <%s>\n",msg); + return; + } + res.room=malloc(roomlen+1); + res.username=malloc(usernamelen+1); + res.message=malloc(textlen+1); + assert(res.room&&res.username&&res.message); + memcpy(res.room,roomp,roomlen); + res.room[roomlen]='\0'; + memcpy(res.username,usernamep,usernamelen); + res.username[usernamelen]='\0'; + memcpy(res.message,textp,textlen); + res.message[textlen]='\0'; + cb(fd,res,payload); + free(res.room); + free(res.username); + free(res.message); + } else if(cmdlen==7&&memcmp(cmd,"history",7)==0){ + struct net_response res; + res.type=NET_OK; + cb(fd,res,payload); + } else if(cmdlen==15&&memcmp(cmd,"history_message",15)==0){ + if(*p=='\0'){ + fprintf(debugf,"net_handle_recv: no arguments to 'history_message' <%s>\n",msg); + return; + } + p=strchr(p+1,' '); + if(*p=='\0'){ + fprintf(debugf,"net_handle_recv: no arguments past index to 'history_message' <%s>\n",msg); + return; + } + const char *roomp=p+1; + p=strchr(roomp,' '); + const char *q,*r; + if(p==NULL||(q=strchr(p+1,' '))==NULL||(r=strchr(q+1,' '))==NULL){ + fprintf(debugf,"net_handle_recv: not enough arguments to 'history_message' <%s>\n",msg); + return; + } + i64 roomlen=p-roomp; + const char *usernamep=p+1; + i64 usernamelen=q-usernamep; + const char *stampp=q+1; + i64 stamplen=r-stampp; + const char *textp=r+1; + i64 textlen=msglen-(textp-msg); + + struct net_response res; + res.type=NET_MESSAGE; + const char *endp; + res.timestamp=strtoll(stampp,(char**)&endp,10); + if(endp-stampp!=stamplen){ + fprintf(debugf,"net_handle_recv: timestamp 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); + assert(res.room&&res.username&&res.message); + memcpy(res.room,roomp,roomlen); + res.room[roomlen]='\0'; + memcpy(res.username,usernamep,usernamelen); + res.username[usernamelen]='\0'; + memcpy(res.message,textp,textlen); + res.message[textlen]='\0'; + cb(fd,res,payload); + free(res.room); + free(res.username); + free(res.message); + } else { + fprintf(debugf,"net_handle_recv: unknown command <%s>\n",msg); + } +} -- cgit v1.2.3-54-g00ecf