ircc.c - ircc - Simple IRC client
 (HTM) git clone git://r-36.net/ircc
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) LICENSE
       ---
       ircc.c (18168B)
       ---
            1 /*
            2  *  Copy me if you can.
            3  *  by 20h
            4  */
            5 
            6 #include <stdlib.h>
            7 #include <string.h>
            8 #include <stdio.h>
            9 #include <stdarg.h>
           10 #include <unistd.h>
           11 #include <fcntl.h>
           12 #include <time.h>
           13 #include <pthread.h>
           14 #include <netdb.h>
           15 #include <sys/types.h>
           16 #include <sys/socket.h>
           17 #include <netinet/in.h>
           18 #include <arpa/inet.h>
           19 #include <openssl/bio.h>
           20 #include <openssl/ssl.h>
           21 #include <openssl/err.h>
           22 #include "arg.h"
           23 
           24 #define VERSION "ircc 3rd ed. Linux 1st ed."
           25 #define nil NULL
           26 
           27 int tls, debug, ignoreflood, anickused, havenickserv, doautojoin;
           28 char *argv0, *lastchan, *clientinfo, *nick, *anick, *passwd;
           29 
           30 typedef struct command command;
           31 struct command {
           32         char **params;
           33         int len;
           34         int isalloc;
           35 };
           36 
           37 command *ignorel, *joinl;
           38 
           39 void *
           40 realloci(void *p, int i, int d)
           41 {
           42         
           43         p = realloc(p, i);
           44         if(p == nil) {
           45                 perror("realloc");
           46                 exit(1);
           47         }
           48 
           49         if(d != 0)
           50                 memset(p, 0, i);
           51 
           52         return (void *)p;
           53 }
           54 
           55 int
           56 swrite(void *sock, char *buf, int l)
           57 {
           58         int ret;
           59 
           60         if(!tls)
           61                 ret = write(*(int *)sock, buf, l);
           62         else {
           63                 ret = BIO_write((BIO *)sock, buf, l);
           64                 (void)BIO_flush((BIO *)sock);
           65         }
           66 
           67         return ret;
           68 }
           69 
           70 int
           71 sread(void *sock, char *buf, int l)
           72 {
           73         int ret;
           74         
           75         if(!tls)
           76                 ret = read(*(int *)sock, buf, l);
           77         else {
           78                 ret = BIO_read((BIO *)sock, buf, l);
           79                 (void)BIO_flush((BIO *)sock);
           80         }
           81 
           82         return ret;
           83 }
           84 
           85 void
           86 tprintf(void *sock, char *fmt, ...)
           87 {
           88         va_list fmtargs;
           89         char buf[8192];
           90 
           91         va_start(fmtargs, fmt);
           92         vsnprintf(buf, sizeof(buf) - 1, fmt, fmtargs);
           93         va_end(fmtargs);
           94 
           95         if(swrite(sock, buf, strlen(buf)) < 0)
           96                 perror("write");
           97 
           98         return;
           99 }
          100 
          101 int
          102 connecttcp(char *host, char *service)
          103 {
          104         int sock;
          105         struct addrinfo *ai, *a;
          106 
          107         sock = -1;
          108 
          109         if(getaddrinfo(host, service, nil, &ai) < 0) {
          110                 perror("getaddrinfo");
          111                 return -1;
          112         }
          113 
          114         for(a = ai; a; a = a->ai_next) {
          115                 sock = socket(a->ai_family, a->ai_socktype, a->ai_protocol);
          116                 if(sock < 0) {
          117                         perror("socket");
          118                         sock = -1;
          119                         break;
          120                 }
          121 
          122                 if(connect(sock, a->ai_addr, a->ai_addrlen) < 0) {        
          123                         perror("connect");
          124                         sock = -1;
          125                         break;
          126                 } else
          127                         break;
          128         }
          129 
          130         freeaddrinfo(ai);
          131 
          132         return sock;
          133 } 
          134 
          135 void
          136 freecmd(command *cmd)
          137 {
          138         int i;
          139 
          140         i = -1;
          141         if(cmd != nil) {
          142                 if(cmd->isalloc)
          143                         while(++i < cmd->len)
          144                                 if(cmd->params[i] != nil)
          145                                         free(cmd->params[i]);
          146                 if(cmd->params != nil)
          147                         free(cmd->params);
          148                 free(cmd);
          149         }
          150 
          151         return;
          152 }
          153 
          154 int
          155 addlist(command *c, char *p)
          156 {
          157         int i;
          158 
          159         i = -1;
          160         if(c != nil) {
          161                 if(c->isalloc) {
          162                         p = strdup(p);
          163                         while(++i < c->len) {
          164                                 if(c->params[i] == nil) {
          165                                         c->params[i] = p;
          166 
          167                                         return 2;
          168                                 }
          169                         }
          170                 }
          171 
          172                 c->len++;
          173                 c->params = realloc(c->params, sizeof(char *) * c->len);
          174                 c->params[c->len - 1] = p;
          175 
          176                 return 1;
          177         }
          178 
          179         return 0;
          180 }
          181 
          182 int
          183 searchlist(command *c, char *p)
          184 {
          185         int i;
          186 
          187         i = -1;
          188         if(c != nil)
          189                 while(++i < c->len)
          190                         if(c->params[i] != nil)
          191                                 if(!strcasecmp(c->params[i], p))
          192                                         return i;
          193 
          194         return -1;
          195 }
          196 
          197 int
          198 dellist(command *c, char *p)
          199 {
          200         int i;
          201         
          202         if(c != nil) {
          203                 i = searchlist(c, p);
          204                 if(i != -1) {
          205                         free(c->params[i]);
          206                         c->params[i] = nil;
          207                         c->len--;
          208                         return 1;
          209                 }
          210         }
          211 
          212         return 0;
          213 }
          214 
          215 command *
          216 parsecmd(command *cmd, char *data, int cmds)
          217 {
          218         command *ret;
          219         char *next, *last, *temp;
          220 
          221         temp = nil;
          222 
          223         if(cmd == nil) {
          224                 ret = realloci(nil, sizeof(command), 2);
          225                 last = data;
          226         } else {
          227                 ret = cmd;
          228                 if(ret->isalloc) {
          229                         temp = strdup(ret->params[ret->len - 1]);
          230                         dellist(ret, ret->params[ret->len - 1]);
          231                 } else {
          232                         ret->len--;
          233                         temp = ret->params[ret->len];
          234                 }
          235                 last = temp;
          236         }
          237         while((next = strchr(last, ' ')) != nil && ret->len < cmds) {
          238                 *next = '\0';
          239                 next++;
          240                 if(last[0] == ':')
          241                         last++;
          242                 addlist(ret, last);
          243                 last = next;
          244         }
          245         if(last[0] == ':')
          246                 last++;
          247         if(last != nil)
          248                 addlist(ret, last);
          249 
          250         if(temp != nil && cmd->isalloc)
          251                 free(temp);
          252 
          253         return ret;
          254 }
          255 
          256 char *
          257 mktimestamp(char bord, char bord_e)
          258 {
          259         time_t tim;
          260         struct tm tm;
          261         char *ret;
          262 
          263         time(&tim);
          264         localtime_r(&tim, &tm);
          265 
          266         ret = malloc(31);
          267         snprintf(ret, 30, "%c%.2d:%.2d%c", bord, tm.tm_hour, tm.tm_min, bord_e);
          268 
          269         return ret;
          270 }
          271 
          272 void
          273 setchan(char *new)
          274 {
          275 
          276         if(lastchan != nil)
          277                 free(lastchan);
          278 
          279         lastchan = realloci(nil, strlen(new) + 1, 2);
          280         strcpy(lastchan, new);
          281 }
          282 
          283 void
          284 autojoin(void *sock)
          285 {
          286         int i;
          287 
          288         for(i = 0; i < joinl->len; i++)
          289                 tprintf(sock, "JOIN %s\r\n", joinl->params[i]);
          290         setchan(joinl->params[joinl->len - 1]);
          291 }
          292 
          293 int
          294 gotcommand(void *sock, char *data, int len)
          295 {
          296         command *cmd;
          297         char *last, *next, *send, *cpy, *test, *tmstmp;
          298         int clen;
          299         time_t tim;
          300 
          301         clen = len;
          302         last = data;
          303         send = realloci(nil, 513, 2);
          304 
          305         while((next = strchr(last, '\n')) !=  nil) {
          306                 *next++ = '\0';
          307                 clen -= (next - last);
          308                 if(*(next - 2) == '\r')
          309                         *(next - 2) = '\0';
          310 
          311                 cpy = strdup(last);
          312                 cmd = parsecmd(nil, last, 3);
          313                 tmstmp = mktimestamp('(', ')');
          314 
          315                 if(cmd->len > 1) {
          316                         if(!strncasecmp(cmd->params[0], "PING", 4)) {
          317                                 tprintf(sock, "PONG %s\r\n", cmd->params[1]);
          318                                 goto c_end;
          319                         }
          320                         if(!strncasecmp(cmd->params[0], "ERROR", 5)) {
          321                                 printf("%sERROR%% %s %s %s\n", tmstmp, cmd->params[1], cmd->params[2], cmd->params[3]);
          322                                 goto c_end;
          323                         }
          324                 }
          325                 if(cmd->len > 2) {
          326                         if(!strncasecmp(cmd->params[1], "JOIN", 4)) {
          327                                 printf("%s(%s) has joined %s\n", tmstmp, cmd->params[0], cmd->params[2]);
          328                                 goto c_end;
          329                         }
          330                         if(!strncasecmp(cmd->params[1], "PART", 4)) {
          331                                 printf("%s(%s) has parted %s\n", tmstmp, cmd->params[0], cmd->params[2]);
          332                                 goto c_end;
          333                         }
          334                         if(!strncasecmp(cmd->params[1], "MODE", 4)) {
          335                                 printf("%s(%s)-m-(%s)%% %s\n", tmstmp, cmd->params[0], cmd->params[2], cmd->params[3]);
          336                                 goto c_end;
          337                         }
          338                         if(!strncasecmp(cmd->params[1], "QUIT", 4)) {
          339                                 printf("%s(%s) has quit (%s %s)\n", tmstmp, cmd->params[0], cmd->params[2], (cmd->len > 3) ? cmd->params[3] : "");
          340                                 goto c_end;
          341                         }
          342                         if((test = strchr(cmd->params[0], '!')) != nil)
          343                                 *test = '\0';
          344                         if(!strncasecmp(cmd->params[1], "NICK", 4)) {
          345                                 printf("%s(%s) changed nick to %s\n", tmstmp, cmd->params[0], cmd->params[2]);
          346                                 if(searchlist(ignorel, cmd->params[0]) != -1) {
          347                                         dellist(ignorel, cmd->params[0]);
          348                                         addlist(ignorel, cmd->params[2]);
          349                                 }
          350                                 goto c_end;
          351                         }
          352                 }
          353                 if(cmd->len > 3) {
          354                         if(strlen(cmd->params[1]) == 3) {
          355                                 if(ignoreflood) {
          356                                         if(!strncasecmp(cmd->params[1], "001", 3) ||
          357                                                         !strncasecmp(cmd->params[1], "002", 3) ||
          358                                                         !strncasecmp(cmd->params[1], "003", 3) ||
          359                                                         !strncasecmp(cmd->params[1], "004", 3) ||
          360                                                         !strncasecmp(cmd->params[1], "005", 3) ||
          361                                                         !strncasecmp(cmd->params[1], "250", 3) ||
          362                                                         !strncasecmp(cmd->params[1], "251", 3) ||
          363                                                         !strncasecmp(cmd->params[1], "252", 3) ||
          364                                                         !strncasecmp(cmd->params[1], "253", 3) ||
          365                                                         !strncasecmp(cmd->params[1], "254", 3) ||
          366                                                         !strncasecmp(cmd->params[1], "255", 3) ||
          367                                                         !strncasecmp(cmd->params[1], "265", 3) ||
          368                                                         !strncasecmp(cmd->params[1], "266", 3) ||
          369                                                         !strncasecmp(cmd->params[1], "317", 3) ||
          370                                                         !strncasecmp(cmd->params[1], "318", 3) ||
          371                                                         !strncasecmp(cmd->params[1], "366", 3) ||
          372                                                         !strncasecmp(cmd->params[1], "375", 3) ||
          373                                                         !strncasecmp(cmd->params[1], "372", 3))
          374                                                 goto c_end;
          375                                 }
          376                                 if(!strncasecmp(cmd->params[1], "376", 3)) {
          377                                         if(doautojoin && (!havenickserv || anickused))
          378                                                 autojoin(sock);
          379                                         goto c_end;
          380                                 }
          381                                         
          382                                 printf("%s(%s)(%s)%% %s\n", tmstmp, cmd->params[0], cmd->params[1], cmd->params[3]);
          383                                 if(!strncasecmp(cmd->params[1], "433", 3) && anick != nil) {
          384                                         if(anickused) {
          385                                                 printf("%s(IRCC)%% Sorry, but nick and anick are used. Try something different.\n", tmstmp);
          386                                                 goto c_end;
          387                                         }
          388                                         tprintf(sock, "NICK %s\r\n", anick);
          389                                         anickused = 1;
          390                                 }
          391                                 goto c_end;
          392                         }
          393                         if(!strncasecmp(cmd->params[1], "INVITE", 6)) {
          394                                 printf("%s(%s) invited you to %s\n", tmstmp, cmd->params[0], cmd->params[3]);
          395                                 goto c_end;
          396                         }
          397                         if(!strncasecmp(cmd->params[1], "TOPIC", 5)) {
          398                                 printf("%s(%s) topicchange in %s to \"%s\"\n", tmstmp, cmd->params[0], cmd->params[2], cmd->params[3]);
          399                                 goto c_end;
          400                         }
          401                         if(!strncasecmp(cmd->params[1], "KICK", 4)) {
          402                                 if(parsecmd(cmd, nil, 4) != nil)
          403                                         printf("%s(%s) kicked %s out of %s \"%s\"\n", tmstmp, cmd->params[0], cmd->params[3], cmd->params[2], cmd->params[4]);
          404                                 else
          405                                         printf("%s(%s) kicked %s out of %s\n", tmstmp, cmd->params[0], cmd->params[3], cmd->params[2]);
          406                                 goto c_end;
          407                         }
          408                         if(searchlist(ignorel, cmd->params[0]) == -1 &&
          409                                 searchlist(ignorel, cmd->params[2]) == -1) {
          410                                 if(!strncasecmp(cmd->params[1], "NOTICE", 6)) {
          411                                         printf("%s(%s|%s)%% %s\n", tmstmp, cmd->params[0], cmd->params[2], cmd->params[3]);
          412                                         if(!strncasecmp(cmd->params[0], "NickServ", 8) && havenickserv) {
          413                                                 printf("in case NickServ\n");
          414                                                 tprintf(sock, "PRIVMSG NickServ :IDENTIFY %s\r\n", passwd);
          415                                                 memset(passwd, 0, strlen(passwd));
          416                                                 havenickserv = 0;
          417                                                 if(doautojoin)
          418                                                         autojoin(sock);
          419                                         }
          420                                         goto c_end;
          421                                 }
          422                                 if(!strncasecmp(cmd->params[1], "PRIVMSG", 7)) {
          423                                         if(*(cmd->params[3]) == '\x01') {
          424                                                 if(!strncasecmp(cmd->params[3]+1, "VERSION", 7))
          425                                                         tprintf(sock, "NOTICE %s :\x01VERSION " VERSION "\x01\r\n", cmd->params[0]);
          426                                                 if(!strncasecmp(cmd->params[3]+1, "TIME", 4)) {
          427                                                         tim = time(0);
          428                                                         test = ctime(&tim);
          429                                                         test[strlen(test) - 1] = '\0';
          430                                                         tprintf(sock, "NOTICE %s :\x01TIME %s\x01\r\n", cmd->params[0], test);
          431                                                 }
          432                                                 if(!strncasecmp(cmd->params[3]+1, "PING", 4))
          433                                                         tprintf(sock, "NOTICE %s :\x01PONG %s\r\n", cmd->params[0], cmd->params[3]+6);
          434                                                 if(!strncasecmp(cmd->params[3]+1, "ACTION", 6)) {
          435                                                         *(cmd->params[3] + strlen(cmd->params[3])-1) = '\0';
          436                                                         printf("%s(%s+%s) %s\n", tmstmp, cmd->params[0], cmd->params[2], cmd->params[3]+8);
          437                                                         goto c_end;
          438                                                 }
          439                                                 if(!strncasecmp(cmd->params[3]+1, "CLIENTINFO", 10))
          440                                                         tprintf(sock, "NOTICE %s :\x01CLIENTINFO PING VERSION TIME USERINFO CLIENTINFO\x01\r\n", cmd->params[0]);
          441                                                 if(!strncasecmp(cmd->params[3]+1, "USERINFO", 8))
          442                                                         tprintf(sock, "NOTICE %s :\x01USERINFO %s\x01\r\n", cmd->params[0], (clientinfo != nil) ? clientinfo : "<nil>");
          443                                         }
          444                                         printf("%s(%s-%s)%% %s\n", tmstmp, cmd->params[0], cmd->params[2], cmd->params[3]);
          445                                         goto c_end;
          446                                 }
          447                                 if(!strncasecmp(cmd->params[0], "NOTICE", 6)) {
          448                                         printf("%sNOTICE%% %s\n", tmstmp, cmd->params[3]);
          449                                         goto c_end;
          450                                 }
          451                         } else
          452                                 goto c_end;
          453                 }
          454                 printf("%s\n",cpy);
          455 c_end:
          456                 free(tmstmp);
          457                 free(cpy);
          458                 freecmd(cmd);
          459                 last = next;
          460         }
          461 
          462         if(clen > 0)
          463                 strcpy(data, data + len - clen);
          464         if(send != nil)
          465                 free(send);
          466 
          467         return clen;
          468 }
          469 
          470 void *
          471 recvproc(void *sock)
          472 {
          473         char *recv;
          474         int len, overl;
          475 
          476         recv = realloci(nil, 1025, 2);
          477         len = 1;
          478         overl = 0;
          479 
          480         while(len > 0 && sock != nil) {
          481                 len = sread(sock, recv + overl, 1024 - overl);
          482 
          483                 if(debug)
          484                         printf("%s\n", recv);
          485                 
          486                 if(len > 1)
          487                         overl = gotcommand(sock, recv, len + overl);
          488         }
          489 
          490         free(recv);
          491 
          492         return nil;
          493 }
          494 
          495 void
          496 usage(void)
          497 {
          498 
          499         fprintf(stdout, "usage: %s [-dit] [-a anick] [-c clientinfo]"
          500                         " [-j #channel ...]"
          501                         " [-k passwd]"
          502                         " [-n nick] [-o port] [-p pass] [-u user]"
          503                         " server\n",
          504                         argv0);
          505 
          506         exit(1);
          507 }
          508 
          509 int
          510 main(int argc, char *argv[])
          511 {
          512         void *sock;
          513         int i, so;
          514         char *send, *rad, *tmstmp, *user, *pass, *port;
          515         command *cmd;
          516         pthread_t th;
          517         BIO *bio;
          518         SSL_CTX *ctx;
          519         SSL *ssl;
          520 
          521         ctx = nil;
          522         user = "root";
          523         pass = nil;
          524         nick = "root";
          525         anick = nil;
          526         port = nil;
          527         tls = 0;
          528         clientinfo = "The user has not specified his details.";
          529         joinl = realloci(nil, sizeof(command), 2);
          530         joinl->isalloc = 1;
          531 
          532         ARGBEGIN {
          533         case 'u':
          534                 user = EARGF(usage());
          535                 break;
          536         case 'p':
          537                 pass = EARGF(usage());
          538                 break;
          539         case 't':
          540                 tls = 1;
          541                 break;
          542         case 'd':
          543                 debug = 1;
          544                 break;
          545         case 'c':
          546                 clientinfo = EARGF(usage());
          547                 break;
          548         case 'i':
          549                 ignoreflood = 1;
          550                 break;
          551         case 'n':
          552                 nick = EARGF(usage());
          553                 break;
          554         case 'o':
          555                 port = EARGF(usage());
          556                 break;
          557         case 'a':
          558                 anick = EARGF(usage());
          559                 break;
          560         case 'k':
          561                 havenickserv = 1;
          562                 passwd = EARGF(usage());
          563                 break;
          564         case 'j':
          565                 addlist(joinl, EARGF(usage()));
          566                 doautojoin = 1;
          567                 break;
          568         default:
          569                 usage();
          570         } ARGEND;
          571                         
          572                         
          573         if(argc < 1)
          574                 usage();
          575 
          576         if(!tls) {        
          577                 so = connecttcp(argv[0], (port == nil)? "6667" : port);
          578                 if(so < 0) {
          579                         perror("connecttcp");
          580                         exit(1);
          581                 }
          582 
          583                 sock = &so;
          584         } else {
          585                 ERR_load_crypto_strings();
          586                 SSL_library_init();
          587 
          588                 ctx = SSL_CTX_new(SSLv23_client_method());
          589                 if(ctx == nil) {
          590                         perror("SSL_CTX_new");
          591                         ERR_print_errors_fp(stderr);
          592                         exit(1);
          593                 }
          594                 bio = BIO_new_ssl_connect(ctx);
          595                 if(bio == nil) {
          596                         perror("BIO_new_ssl_connect");
          597                         ERR_print_errors_fp(stderr);
          598                         exit(1);
          599                 }
          600 
          601                 BIO_get_ssl(bio, &ssl);
          602                 SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);        
          603 
          604                 BIO_set_conn_port(bio, (port == nil)? "994" : port);
          605                 BIO_set_conn_hostname(bio, argv[0]); 
          606                 if(BIO_do_connect(bio) <= 0) {
          607                         perror("BIO_do_connect");
          608                         ERR_print_errors_fp(stderr);
          609                         exit(1);
          610                 }
          611 
          612                 sock = bio;
          613         }
          614 
          615         if(user == nil)
          616                 user = nick;
          617 
          618         if(pass != nil)
          619                 tprintf(sock, "PASS %s\r\n", pass);
          620         tprintf(sock, "NICK %s\r\n", nick);
          621         tprintf(sock, "USER %s localhost %s :%s\r\n", user, nick, user);
          622 
          623         if(pthread_create(&th, nil, recvproc, sock) < 0) {
          624                 perror("pthread_create");
          625                 exit(1);
          626         }
          627 
          628         ignorel = realloci(nil, sizeof(command), 2);
          629         ignorel->isalloc = 1;
          630         send = realloci(nil, 513, 2);
          631         rad = realloci(nil, 513, 2);
          632 
          633         while(sock > 0) {
          634                 i = -1;
          635                 cmd = nil;
          636                 memset(send, 0, 513);
          637                 memset(rad, 0, 513);
          638 
          639                 while(read(0, &rad[++i], 1) && i < 400 && sock != nil) {
          640                         if(rad[i] == '\n') {
          641                                 rad[i] = '\0';
          642                                 break;
          643                         }
          644                 }
          645                 rad[i + 1] = '\0';
          646 
          647                 tmstmp = mktimestamp('(', ')');
          648                 if(rad[0] == '/')
          649                         cmd = parsecmd(nil, rad, 2);
          650 
          651                 if(cmd != nil) {
          652                         if(cmd->len > 0) {
          653                                 switch(cmd->params[0][1]) {
          654                                 case 'H':
          655                                 case 'h':
          656                                         printf("%s Help for ircc:\n", tmstmp);
          657                                         printf("%s   /a chan text - send /me text to chan\n", tmstmp);
          658                                         printf("%s   /c chan what - send CTCP what to chan\n", tmstmp);
          659                                         printf("%s   /d - turn debugging on or off\n", tmstmp);
          660                                         printf("%s   /h - show this help\n", tmstmp);
          661                                         printf("%s   /i chan - ignore/unignore chan\n", tmstmp);
          662                                         printf("%s   /j chan - join chan\n", tmstmp);
          663                                         printf("%s   /k user [readon] - kick a user\n", tmstmp);
          664                                         printf("%s   /l [chan] - list channels on server\n", tmstmp);
          665                                         printf("%s   /m chan text - send text to chan\n", tmstmp);
          666                                         printf("%s   /n nick - change nickname to nick\n", tmstmp);
          667                                         printf("%s   /o chan mode [user] - set mode on chan\n", tmstmp);
          668                                         printf("%s   /p chan - part chan\n", tmstmp);
          669                                         printf("%s   /q [msg] - quit ircc\n", tmstmp);
          670                                         printf("%s   /s chan - set active chan\n", tmstmp);
          671                                         printf("%s   /t chan [topic] - set/show topic of chan\n", tmstmp);
          672                                         printf("%s   /u chan - WHO of chan\n", tmstmp);
          673                                         printf("%s   /w chan - WHOIS of chan\n", tmstmp);
          674                                         goto end_e;
          675                                 case 'D':
          676                                 case 'd':
          677                                         if(debug)
          678                                                 debug = 0;
          679                                         else
          680                                                 debug = 1;
          681                                         printf("%s debug %d\n", tmstmp, debug);
          682                                         goto end_e;
          683                                 case 'Q':
          684                                 case 'q':
          685                                         sprintf(send, "QUIT :\r\n");
          686                                         if(cmd->len == 2)
          687                                                 sprintf(send + 6, "%s\r\n", cmd->params[1]);
          688                                         if(cmd->len > 2)
          689                                                 sprintf(send + 6, "%s %s\r\n", cmd->params[1], cmd->params[2]);
          690                                         swrite(sock, send, strlen(send));
          691                                         if(tls)
          692                                                 BIO_free_all(sock);
          693                                         else
          694                                                 close(*(int *)sock);
          695                                         sock = nil;
          696                                         goto end_e;
          697                                 case 'L':
          698                                 case 'l':
          699                                         sprintf(send, "LIST\r\n");
          700                                         if(cmd->len == 2)
          701                                                 sprintf(send + 4, " %s\r\n", cmd->params[1]);
          702                                         if(cmd->len > 2)
          703                                                 sprintf(send + 4, " %s %s\r\n", cmd->params[1], cmd->params[2]);
          704                                         swrite(sock, send, strlen(send));
          705                                         goto end_e;
          706                                 case 'S':
          707                                 case 's':
          708                                         if(cmd->len > 1)
          709                                                 setchan(cmd->params[1]);
          710                                         else
          711                                                 printf("%s\n", (lastchan == nil) ? "<nil>": lastchan);
          712                                         goto end_e;
          713                                 default:
          714                                         break;
          715                                 }
          716                         }
          717                         if(cmd->len > 1) {
          718                                 switch(cmd->params[0][1]) {
          719                                 case 'J':
          720                                 case 'j':
          721                                         tprintf(sock, "JOIN %s\r\n", cmd->params[1]);
          722                                         setchan(cmd->params[1]);
          723                                         goto end_e;
          724                                 case 'P':
          725                                 case 'p':
          726                                         tprintf(sock, "PART %s\r\n", cmd->params[1]);
          727                                         goto end_e;
          728                                 case 'N':
          729                                 case 'n':
          730                                         tprintf(sock, "NICK %s\r\n", cmd->params[1]);
          731                                         goto end_e;
          732                                 case 'W':
          733                                 case 'w':
          734                                         tprintf(sock, "WHOIS %s\r\n", cmd->params[1]);
          735                                         goto end_e;
          736                                 case 'U':
          737                                 case 'u':
          738                                         tprintf(sock, "WHO %s\r\n", cmd->params[1]);
          739                                         goto end_e;
          740                                 case 'T':
          741                                 case 't':
          742                                         sprintf(send, "TOPIC %s\r\n", cmd->params[1]);
          743                                         if(cmd->len > 2)
          744                                                 sprintf(send + strlen(send) - 2, " :%s\r\n", cmd->params[2]);
          745                                         tprintf(sock, send);
          746                                         goto end_e;
          747                                 case 'I':
          748                                 case 'i':
          749                                         if(searchlist(ignorel, cmd->params[1]) != -1) {
          750                                                 dellist(ignorel, cmd->params[1]);
          751                                                 printf("%s no more ignored. %d\n", cmd->params[1], searchlist(ignorel, cmd->params[1]));
          752                                         } else {
          753                                                 addlist(ignorel, cmd->params[1]);
          754                                                 printf("%s will be ignored.\n", cmd->params[1]);
          755                                         }
          756                                         goto end_e;
          757                                 default:
          758                                         break;
          759                                 }
          760                         }
          761                         if(cmd->len > 2) {
          762                                 switch(cmd->params[0][1]) {
          763                                 case 'M':
          764                                 case 'm':
          765                                         tprintf(sock, "PRIVMSG %s :%s\r\n", cmd->params[1], cmd->params[2]);
          766                                         goto end_e;
          767                                 case 'A':
          768                                 case 'a':
          769                                         tprintf(sock, "PRIVMSG %s :%sACTION %s\x01\r\n", "\x01", cmd->params[1], cmd->params[2]);
          770                                         goto end_e;
          771                                 case 'O':
          772                                 case 'o':
          773                                         if(cmd->len > 3)
          774                                                 tprintf(sock, "MODE %s %s %s\r\n", cmd->params[1], cmd->params[2], cmd->params[3]);
          775                                         else
          776                                                 tprintf(sock, "MODE %s %s\r\n", cmd->params[1], cmd->params[2]);
          777                                         goto end_e;
          778                                 case 'C':
          779                                 case 'c':
          780                                         printf("%s(%s) ctcp %s\n", tmstmp, cmd->params[1], cmd->params[2]);
          781                                         tprintf(sock, "PRIVMSG %s :\x01%s\x01\r\n", cmd->params[1], cmd->params[2]);
          782                                         goto end_e;
          783                                 case 'K':
          784                                 case 'k':
          785                                         sprintf(send, "KICK %s %s\r\n", cmd->params[1], cmd->params[2]);
          786                                         if(cmd->len > 3)
          787                                                 sprintf(send + strlen(send) - 2, " :%s\r\n", cmd->params[3]);
          788                                         tprintf(sock, send);
          789                                         goto end_e;
          790                                 default:
          791                                         break;
          792                                 }
          793                         }
          794                 }
          795                 if(lastchan != nil)
          796                         tprintf(sock, "PRIVMSG %s :%s\r\n", lastchan, rad);
          797                 else
          798                         printf(".");
          799 end_e:
          800                 printf("%s\n", tmstmp);
          801                 free(tmstmp);
          802                 freecmd(cmd);
          803         }
          804 
          805         if(lastchan != nil)
          806                 free(lastchan);
          807         free(send);
          808         free(rad);
          809         freecmd(ignorel);
          810         freecmd(joinl);
          811         if(tls)
          812                 SSL_CTX_free(ctx);
          813 
          814         return 0;
          815 }
          816