diff -r d93eaacde742 ii.c --- a/ii.c Fri Jun 25 10:55:05 2010 +0200 +++ b/ii.c Tue Jul 27 17:48:23 2010 -0500 @@ -26,10 +26,17 @@ enum { TOK_NICKSRV = 0, TOK_USER, TOK_CMD, TOK_CHAN, TOK_ARG, TOK_TEXT, TOK_LAST }; +typedef struct Nick Nick; +struct Nick { + char *name; + Nick *next; +}; + typedef struct Channel Channel; struct Channel { int fd; char *name; + Nick *nicks; Channel *next; }; @@ -128,18 +135,25 @@ c->next = channels; channels = c; } + c->nicks = NULL; c->fd = fd; c->name = strdup(name); } static void rm_channel(Channel *c) { Channel *p; + Nick *n, *nn; if(channels == c) channels = channels->next; else { for(p = channels; p && p->next != c; p = p->next); if(p->next == c) p->next = c->next; } + for(n = c->nicks; n; n = nn) { + nn = n->next; + free(n->name); + free(n); + } free(c->name); free(c); } @@ -217,6 +231,76 @@ fclose(out); } +static Channel *lookup_chan(const char *name) { + Channel *c; + for(c = channels; c; c = c->next) + if(!strcmp(name, c->name)) + return c; + return NULL; +} + +static void add_name(const char *chan, const char *name) { + Channel *c; + Nick *n; + if(!(c = lookup_chan(chan))) return; + for(n = c->nicks; n; n = n->next) + if(!strcmp(name, n->name)) return; + if(!(n = malloc(sizeof(Nick)))) { + perror("ii: cannot allocate memory"); + exit(EXIT_FAILURE); + } + n->name = strdup(name); + n->next = c->nicks; + c->nicks = n; +} + +static int rm_name(const char *chan, const char *name) { + Channel *c; + Nick *n, *pn = NULL; + if(!(c = lookup_chan(chan))) return 0; + for(n = c->nicks; n; pn = n, n = n->next) { + if(!strcmp(name, n->name)) { + if(pn) pn->next = n->next; + else c->nicks = n->next; + free(n->name); + free(n); + return 1; + } + } + return 0; +} + +static void proc_names(const char *chan, char *names) { + char *p; + if(!(p = strtok(names," "))) return; + do { + if(*p == '@' || *p == '+') + p++; + add_name(chan,p); + } while((p = strtok(NULL," "))); +} + +static void quit_name(const char *name, const char *user, const char *text) { + Channel *c; + for(c = channels; c; c = c->next) { + if(c->name && rm_name(c->name, name)) { + snprintf(message, PIPE_BUF, "-!- %s(%s) has quit \"%s\"", name, user, text ? text : ""); + print_out(c->name, message); + } + } +} + +static void nick_name(const char *old, const char *new) { + Channel *c; + for(c = channels; c; c = c->next) { + if(c->name && rm_name(c->name, old)) { + add_name(c->name, new); + snprintf(message, PIPE_BUF, "-!- %s changed nick to \"%s\"", old, new); + print_out(c->name, message); + } + } +} + static void proc_channels_privmsg(char *channel, char *buf) { snprintf(message, PIPE_BUF, "<%s> %s", nick, buf); print_out(channel, message); @@ -342,6 +426,14 @@ snprintf(message, PIPE_BUF, "PONG %s\r\n", argv[TOK_TEXT]); write(irc, message, strlen(message)); return; + } else if(!strncmp("353", argv[TOK_CMD], 4)) { + p = strtok(argv[TOK_ARG]," "); + if(!(p = strtok(NULL," "))) + return; + snprintf(message, PIPE_BUF, "%s%s", argv[TOK_ARG] ? argv[TOK_ARG] : "", argv[TOK_TEXT] ? argv[TOK_TEXT] : ""); + print_out(0, message); + proc_names(p, argv[TOK_TEXT]); + return; } else if(!argv[TOK_NICKSRV] || !argv[TOK_USER]) { /* server command */ snprintf(message, PIPE_BUF, "%s%s", argv[TOK_ARG] ? argv[TOK_ARG] : "", argv[TOK_TEXT] ? argv[TOK_TEXT] : ""); print_out(0, message); @@ -356,19 +448,24 @@ } argv[TOK_CHAN] = argv[TOK_TEXT]; snprintf(message, PIPE_BUF, "-!- %s(%s) has joined %s", argv[TOK_NICKSRV], argv[TOK_USER], argv[TOK_TEXT]); + add_name(argv[TOK_CHAN],argv[TOK_NICKSRV]); } else if(!strncmp("PART", argv[TOK_CMD], 5)) { snprintf(message, PIPE_BUF, "-!- %s(%s) has left %s", argv[TOK_NICKSRV], argv[TOK_USER], argv[TOK_CHAN]); + rm_name(argv[TOK_CHAN],argv[TOK_NICKSRV]); } else if(!strncmp("MODE", argv[TOK_CMD], 5)) snprintf(message, PIPE_BUF, "-!- %s changed mode/%s -> %s %s", argv[TOK_NICKSRV], argv[TOK_CMD + 1] ? argv[TOK_CMD + 1] : "" , argv[TOK_CMD + 2]? argv[TOK_CMD + 2] : "", argv[TOK_CMD + 3] ? argv[TOK_CMD + 3] : ""); - else if(!strncmp("QUIT", argv[TOK_CMD], 5)) - snprintf(message, PIPE_BUF, "-!- %s(%s) has quit \"%s\"", argv[TOK_NICKSRV], argv[TOK_USER], argv[TOK_TEXT] ? argv[TOK_TEXT] : ""); - else if(!strncmp("NICK", argv[TOK_CMD], 5)) - snprintf(message, PIPE_BUF, "-!- %s changed nick to %s", argv[TOK_NICKSRV], argv[TOK_TEXT]); - else if(!strncmp("TOPIC", argv[TOK_CMD], 6)) + else if(!strncmp("QUIT", argv[TOK_CMD], 5)) { + quit_name(argv[TOK_NICKSRV], argv[TOK_USER], argv[TOK_TEXT]); + return; + } else if(!strncmp("NICK", argv[TOK_CMD], 5)) { + nick_name(argv[TOK_NICKSRV], argv[TOK_TEXT]); + return; + } else if(!strncmp("TOPIC", argv[TOK_CMD], 6)) snprintf(message, PIPE_BUF, "-!- %s changed topic to \"%s\"", argv[TOK_NICKSRV], argv[TOK_TEXT] ? argv[TOK_TEXT] : ""); - else if(!strncmp("KICK", argv[TOK_CMD], 5)) + else if(!strncmp("KICK", argv[TOK_CMD], 5)) { snprintf(message, PIPE_BUF, "-!- %s kicked %s (\"%s\")", argv[TOK_NICKSRV], argv[TOK_ARG], argv[TOK_TEXT] ? argv[TOK_TEXT] : ""); - else if(!strncmp("NOTICE", argv[TOK_CMD], 7)) + rm_name(argv[TOK_CHAN],argv[TOK_NICKSRV]); + } else if(!strncmp("NOTICE", argv[TOK_CMD], 7)) snprintf(message, PIPE_BUF, "-!- \"%s\")", argv[TOK_TEXT] ? argv[TOK_TEXT] : ""); else if(!strncmp("PRIVMSG", argv[TOK_CMD], 8)) snprintf(message, PIPE_BUF, "<%s> %s", argv[TOK_NICKSRV], argv[TOK_TEXT] ? argv[TOK_TEXT] : "");