Permalink
Browse files

Implemented MODEs, except that nick-prefixes are never displayed

  • Loading branch information...
1 parent f998834 commit cdd4d11c634156624a8b52984ee7f9178f796651 ec429 committed Dec 24, 2011
Showing with 233 additions and 21 deletions.
  1. +43 −12 buffer.c
  2. +1 −1 buffer.h
  3. +184 −3 irc.c
  4. +1 −1 irc.h
  5. +2 −2 names.c
  6. +1 −1 plans
  7. +1 −1 quirc.c
View
@@ -101,6 +101,7 @@ int init_buffer(int buf, btype type, const char *bname, int nlines)
bufs[buf].bname=strdup(bname);
bufs[buf].realsname=NULL;
bufs[buf].nlist=NULL;
+ bufs[buf].us=NULL;
bufs[buf].ilist=NULL;
bufs[buf].handle=0;
bufs[buf].server=0;
@@ -141,10 +142,18 @@ int init_buffer(int buf, btype type, const char *bname, int nlines)
bufs[buf].conninpr=false;
initibuf(&bufs[buf].input);
bufs[buf].casemapping=RFC1459;
- bufs[buf].npfx=2;
- bufs[buf].prefixes=malloc(2*sizeof(prefix));
- bufs[buf].prefixes[0]=(prefix){.letter='o', .pfx='@'};
- bufs[buf].prefixes[1]=(prefix){.letter='v', .pfx='+'};
+ if(type==SERVER)
+ {
+ bufs[buf].npfx=2;
+ bufs[buf].prefixes=malloc(2*sizeof(prefix));
+ bufs[buf].prefixes[0]=(prefix){.letter='o', .pfx='@'};
+ bufs[buf].prefixes[1]=(prefix){.letter='v', .pfx='+'};
+ }
+ else
+ {
+ bufs[buf].npfx=0;
+ bufs[buf].prefixes=NULL;
+ }
bufs[buf].autoent=NULL;
return(0);
}
@@ -804,27 +813,33 @@ void titlebar(void)
char *cserv=strdup(bufs[bufs[cbuf].server].bname?bufs[bufs[cbuf].server].bname:"");
char *cnick=strdup(bufs[bufs[cbuf].server].nick?bufs[bufs[cbuf].server].nick:"");
char *cchan=strdup(((bufs[cbuf].type==CHANNEL)||(bufs[cbuf].type==PRIVATE))&&bufs[cbuf].bname?bufs[cbuf].bname:"");
+ size_t chanlen=strlen(cchan)+1, nicklen=strlen(cnick)+1;
+ if(bufs[cbuf].type==CHANNEL)
+ {
+ if(bufs[cbuf].npfx) chanlen+=2+bufs[cbuf].npfx;
+ if((bufs[cbuf].us)&&(bufs[cbuf].us->npfx)) nicklen+=2+bufs[cbuf].us->npfx;
+ }
char *topic=(bufs[cbuf].type==CHANNEL)?bufs[cbuf].topic:NULL;
scrush(&cserv, 16);
crush(&cnick, 16);
crush(&cchan, 16);
char tbar[width];
unsigned int wleft=width-1;
- bool use[8]; // #chan nick quIRC version gits ghashgit server topic...
+ bool use[8]; // #chan(modes) nick(modes) quIRC version gits ghashgit server topic...
char version[32];
sprintf(version, "%hhu.%hhu.%hhu", VERSION_MAJ, VERSION_MIN, VERSION_REV);
char vgits[8];
sprintf(vgits, "%hhu", gits);
memset(use, 0, sizeof(bool[8]));
- if(*cchan && (wleft>=strlen(cchan)+1))
+ if(*cchan && (wleft>=chanlen))
{
use[0]=true;
- wleft-=strlen(cchan)+1;
+ wleft-=chanlen;
}
- if(*cnick && (wleft>=strlen(cnick)+1))
+ if(*cnick && (wleft>=nicklen))
{
use[1]=true;
- wleft-=strlen(cnick)+1;
+ wleft-=nicklen;
}
if(wleft>=6)
{
@@ -866,7 +881,7 @@ void titlebar(void)
tbar[i]='-';
tbar[width]=0;
int p=1;
- // 2quIRC 3version 4gits 5ghashgit 6server 0chan 1nick 7topic
+ // 2quIRC 3version 4gits 5ghashgit 6server 0chan(m) 1nick(m) 7topic
// 0#chan 1nick 2quIRC 3version 4gits 5ghashgit 6server 7topic...
if(use[2])
{
@@ -896,12 +911,28 @@ void titlebar(void)
if(use[0])
{
memcpy(tbar+p, cchan, strlen(cchan));
- p+=strlen(cchan)+1;
+ p+=strlen(cchan);
+ if((bufs[cbuf].type==CHANNEL)&&(bufs[cbuf].npfx))
+ {
+ tbar[p++]='(';
+ for(unsigned int i=0;i<bufs[cbuf].npfx;i++)
+ tbar[p++]=bufs[cbuf].prefixes[i].letter;
+ tbar[p++]=')';
+ }
+ p++;
}
if(use[1])
{
memcpy(tbar+p, cnick, strlen(cnick));
- p+=strlen(cnick)+1;
+ p+=strlen(cnick);
+ if((bufs[cbuf].type==CHANNEL)&&(bufs[cbuf].us)&&(bufs[cbuf].us->npfx))
+ {
+ tbar[p++]='(';
+ for(unsigned int i=0;i<bufs[cbuf].us->npfx;i++)
+ tbar[p++]=bufs[cbuf].us->prefixes[i].letter;
+ tbar[p++]=')';
+ }
+ p++;
}
if(use[7])
{
View
@@ -71,7 +71,7 @@ typedef struct _buf
bool conninpr; // connection in progress? (SERVER only)
ibuffer input; // input history
cmap casemapping; // the SERVER's value is authoritative; the CHANNEL's value is ignored. STATUS's value is irrelevant. Set by ISUPPORT
- unsigned int npfx;// ^^
+ unsigned int npfx;// the SERVER's value denotes the available list (set by ISUPPORT); the CHANNEL's value lists the modes set on that channel (letter only)
prefix *prefixes; // ^^
servlist * autoent; // if this was opened by autoconnect(), this is filled in to point to the server's servlist entry
bool conf; // Conference Mode (hides joins, parts, quits, and /nicks)
View
@@ -820,11 +820,12 @@ int rx_ping(message pkt, int b)
return(irc_tx(bufs[bufs[b].server].handle, pong));
}
-int rx_mode(int b)
+int rx_mode(message pkt, int b)
{
// MODE <nick> ({\+|-}{i|w|o|O|r}*)*
- // We don't recognise modes yet, other than as a trigger for auto-join
+ // or MODE <channel> {[\+|-]|o|p|s|i|t|n|b|v} [<limit>] [<user>] [<ban mask>]
int fd=bufs[b].handle;
+ // If appropriate, trigger auto-join
servlist *serv=bufs[b].autoent;
if(autojoin && serv && serv->chans && !serv->join)
{
@@ -841,6 +842,186 @@ int rx_mode(int b)
}
serv->join=true;
}
+ if(pkt.nargs<2)
+ {
+ if(!quiet) e_buf_print(b, c_err, pkt, "Not enough arguments: ");
+ return(0);
+ }
+ for(int b2=0;b2<nbufs;b2++)
+ {
+ if((bufs[b2].type==CHANNEL)&&(bufs[b2].server==b)&&(irc_strcasecmp(pkt.args[0], bufs[b2].bname, bufs[b].casemapping)==0))
+ {
+ bool plus=false;
+ switch(*pkt.args[1])
+ {
+ case '+':
+ plus=true;
+ case '-':; /* fallthrough */
+ unsigned int i;
+ for(i=0;i<bufs[b].npfx;i++)
+ {
+ if(bufs[b].prefixes[i].letter==pkt.args[1][1])
+ {
+ // user expected
+ if(pkt.nargs<3)
+ {
+ if(!quiet) e_buf_print(b, c_err, pkt, "Not enough arguments: ");
+ return(0);
+ }
+ name *curr=bufs[b2].nlist;
+ while(curr)
+ {
+ if(irc_strcasecmp(curr->data, pkt.args[2], bufs[b].casemapping)==0)
+ {
+ bool found=false;
+ for(unsigned int j=0;j<curr->npfx;j++)
+ {
+ if(curr->prefixes[j].letter==pkt.args[1][1])
+ {
+ if(plus)
+ found=true;
+ else
+ {
+ curr->npfx--;
+ for(unsigned int k=j;k<curr->npfx;k++)
+ curr->prefixes[k]=curr->prefixes[k+1];
+ }
+ }
+ }
+ if(plus&&!found)
+ {
+ unsigned int n=curr->npfx++;
+ prefix *pfx=realloc(curr->prefixes, curr->npfx*sizeof(prefix));
+ if(pfx)
+ (curr->prefixes=pfx)[n]=bufs[b].prefixes[i];
+ else
+ curr->npfx=n;
+ }
+ break;
+ }
+ curr=curr->next;
+ }
+ if(!curr)
+ if(!quiet) e_buf_print(b, c_err, pkt, "No such nick: ");
+ break;
+ }
+ }
+ if(i==bufs[b].npfx)
+ {
+ // it's a channel mode
+ bool found=false;
+ for(i=0;i<bufs[b2].npfx;i++)
+ {
+ if(bufs[b2].prefixes[i].letter==pkt.args[1][1])
+ {
+ if(plus)
+ found=true;
+ else
+ {
+ bufs[b2].npfx--;
+ for(unsigned int j=i;j<bufs[b2].npfx;j++)
+ bufs[b2].prefixes[j]=bufs[b2].prefixes[j+1];
+ }
+ }
+ }
+ if(plus&&!found)
+ {
+ unsigned int n=bufs[b2].npfx++;
+ prefix *pfx=realloc(bufs[b2].prefixes, bufs[b2].npfx*sizeof(prefix));
+ if(pfx)
+ (bufs[b2].prefixes=pfx)[n]=(prefix){.letter=pkt.args[1][1], .pfx=0}; // channel modes don't have associated prefixes
+ else
+ bufs[b2].npfx=n;
+ }
+ }
+ break;
+ default:
+ if(!quiet) e_buf_print(b, c_err, pkt, "Malformed modespec - missing +/-: ");
+ break;
+ }
+ }
+ }
+ if(tsb)
+ titlebar();
+#if 0 // somewhat broken usermode handling (broken in that it writes to places that store /channel/-usermodes)
+ // Find the nick in the nlist and apply the MODE changes
+ bool found=false;
+ for(int b2=0;b2<nbufs;b2++)
+ {
+ if((bufs[b2].type==CHANNEL)&&(bufs[b2].server==b))
+ {
+ name *curr=bufs[b].nlist;
+ while(curr)
+ {
+ if(irc_strcasecmp(curr->data, pkt.args[0], bufs[b].casemapping)==0)
+ {
+ bool malformed=false;
+ for(int i=1;i<pkt.nargs;i++)
+ {
+ const char *ms=pkt.args[i];
+ switch(*ms)
+ {
+ case '+':
+ while(*++ms)
+ {
+ bool found=false;
+ for(unsigned int j=0;j<curr->npfx;j++)
+ {
+ if(*ms==curr->prefixes[j].letter)
+ {
+ found=true;
+ break;
+ }
+ }
+ if(!found)
+ {
+ for(unsigned int j=0;j<bufs[b].npfx;j++)
+ {
+ if(bufs[b].prefixes[j].letter==*ms)
+ {
+ unsigned int n=curr->npfx++;
+ prefix *pfx=realloc(curr->prefixes, curr->npfx*sizeof(prefix));
+ if(pfx)
+ (curr->prefixes=pfx)[n]=bufs[b].prefixes[j];
+ else
+ curr->npfx=n;
+ break;
+ }
+ }
+ }
+ }
+ break;
+ case '-':
+ while(*++ms)
+ {
+ for(unsigned int j=0;j<curr->npfx;j++)
+ {
+ if(*ms==curr->prefixes[j].letter)
+ {
+ curr->npfx--;
+ for(unsigned int k=j;k<curr->npfx;k++)
+ curr->prefixes[k]=curr->prefixes[k+1];
+ }
+ }
+ }
+ break;
+ default:
+ malformed=true;
+ break;
+ }
+ }
+ if(malformed)
+ if(!quiet) e_buf_print(b, c_err, pkt, "Malformed modespec - missing +/-: ");
+ break;
+ }
+ curr=curr->next;
+ }
+ if(curr) found=true;
+ }
+ }
+ if(!found)
+ if(!quiet) e_buf_print(b, c_err, pkt, "No such nick: ");
+#endif
return(0);
}
@@ -1298,7 +1479,7 @@ int rx_nick(message pkt, int b)
{
add_to_buffer(b2, c_nick[1], dstr, "");
n_cull(&bufs[b2].nlist, src, bufs[b].casemapping);
- n_add(&bufs[b2].nlist, pkt.args[0], bufs[b].casemapping);
+ bufs[b2].us=n_add(&bufs[b2].nlist, pkt.args[0], bufs[b].casemapping);
}
}
}
View
@@ -77,7 +77,7 @@ int talk(char *iinput);
// Received-IRC message handlers
int irc_numeric(message pkt, int b);
int rx_ping(message pkt, int b);
-int rx_mode(int b); // the first MODE triggers auto-join. Apart from using it as a trigger, we don't look at modes just yet
+int rx_mode(message pkt, int b); // the first MODE triggers auto-join
int rx_kill(message pkt, int b, fd_set *master);
int rx_kick(message pkt, int b);
int rx_error(message pkt, int b, fd_set *master);
View
@@ -103,8 +103,8 @@ void n_free(name * list)
if(list)
{
n_free(list->next);
- if(list->data)
- free(list->data);
+ free(list->data);
+ free(list->prefixes);
free(list);
}
}
View
@@ -32,7 +32,7 @@ Const-correctness. There are a lot of functions taking a char * that should tak
Remember channel keys for /rejoin. An argument to /rejoin overrides (but doesn't overwrite unless the /rejoin succeeds).
-Modes. It's really about time I got those sorted out.
+/set prefix. Toggle display of nick prefixes.
Proper handling of Unicode in character-based things like cursor-movement, backspace.
View
@@ -347,7 +347,7 @@ int main(int argc, char *argv[])
}
else if(strcmp(pkt.cmd, "MODE")==0)
{
- rx_mode(b);
+ rx_mode(pkt, b);
}
else if(strcmp(pkt.cmd, "KILL")==0)
{

0 comments on commit cdd4d11

Please sign in to comment.