Updated po files
[centerim.git] / firetalk / irc.c
blob6cf3c819d8ce0eda2a5f99bbc919a7509675497f
1 /*
2 irc.c - FireTalk IRC protocol driver
3 Copyright (C) 2000 Ian Gulliver
4 Copyright 2002-2006 Daniel Reed <n@ml.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of version 2 of the GNU General Public License as
8 published by the Free Software Foundation.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include <assert.h>
20 #include <ctype.h>
21 #include <errno.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <netdb.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32 #include <strings.h>
33 #include <sys/time.h>
34 #include <time.h>
36 #define ROOMSTARTS "#+&"
39 static char irc_tolower(const char c) {
40 if ((c >= 'A') && (c <= 'Z'))
41 return((c - 'A') + 'a');
42 if (c == '[')
43 return('{');
44 if (c == ']')
45 return('{');
46 if (c == '\\')
47 return('|');
48 return(c);
51 static int irc_compare_nicks_int(const char *const nick1, const char *const nick2) {
52 int i = 0;
54 while (nick1[i] != '\0') {
55 if (irc_tolower(nick1[i]) != irc_tolower(nick2[i]))
56 return(1);
57 i++;
59 if (nick2[i] != '\0')
60 return(1);
62 return(0);
65 struct s_irc_whois {
66 struct s_irc_whois *next;
67 char *nickname,
68 *info;
69 int flags;
70 long online,
71 idle;
74 typedef struct irc_conn_t *client_t;
75 #define _HAVE_CLIENT_T
76 #include "firetalk-int.h"
78 typedef struct irc_conn_t {
79 char *nickname,
80 *password,
81 buffer[512+1];
82 struct s_irc_whois
83 *whois_head;
84 int passchange; /* whether we are currently changing our pass */
85 unsigned char
86 usesilence:1, /* are we on a network that understands SILENCE */
87 identified:1; /* are we we identified */
88 } irc_conn_t;
90 #if 0
91 static const char *const irc_normalize_user_nick(const char *const name) {
92 static char
93 buf[512];
94 int i;
96 if (strchr(name, '!') == NULL)
97 return(name);
99 for (i = 0; (i < sizeof(buf)) && (name[i] != '!'); i++)
100 buf[i] = name[i];
101 buf[i] = 0;
102 return(buf);
105 static const char *const irc_normalize_user_mask(const char *const name) {
106 static char
107 buf[512];
109 if (strchr(name, '!') != NULL)
110 return(name);
112 snprintf(buf, sizeof(buf), "%s!*@*", name);
113 return(buf);
115 #endif
117 static void irc_disc_user_rem(irc_conn_t *c, const char *disc, const char *name) {
118 struct s_firetalk_handle *fchandle;
120 fchandle = firetalk_find_handle(c);
122 if (firetalk_user_visible_but(fchandle, disc, name) == FE_NOMATCH)
123 firetalk_callback_im_buddyonline(c, name, 0);
126 static void irc_disc_rem(irc_conn_t *c, const char *disc) {
127 struct s_firetalk_handle *fchandle;
128 struct s_firetalk_room *iter;
129 struct s_firetalk_member *mem;
131 fchandle = firetalk_find_handle(c);
132 iter = firetalk_find_room(fchandle, disc);
133 assert(iter != NULL);
135 for (mem = iter->member_head; mem != NULL; mem = mem->next)
136 irc_disc_user_rem(c, disc, mem->nickname);
139 static const char *irc_normalize_room_name(const char *const name) {
140 static char newname[2048];
142 if (strchr(ROOMSTARTS, *name))
143 return(name);
144 snprintf(newname, sizeof(newname), "#%s", name);
145 return(newname);
150 #include "firetalk.h"
154 #ifdef DEBUG_ECHO
155 extern void *curconn;
156 extern void status_echof(void *conn, const unsigned char *format, ...);
158 static void irc_echof(irc_conn_t *c, const char *const where, const char *const format, ...) {
159 va_list ap;
160 char buf[513];
161 void statrefresh(void);
163 va_start(ap, format);
164 vsnprintf(buf, sizeof(buf), format, ap);
165 va_end(ap);
167 while (buf[strlen(buf)-1] == '\n')
168 buf[strlen(buf)-1] = 0;
169 if (*buf != 0)
170 status_echof(curconn, firetalk_htmlentities(buf));
171 // firetalk_callback_chat_getmessage(c, ":RAW", where, 0, buf);
173 statrefresh();
175 #endif
177 static fte_t irc_compare_nicks(const char *const nick1, const char *const nick2) {
178 if (irc_compare_nicks_int(nick1, nick2) == 0)
179 return(FE_SUCCESS);
180 return(FE_NOMATCH);
183 static fte_t
184 irc_isprint(const int c) {
185 if (isprint(c))
186 return(FE_SUCCESS);
187 return(FE_INVALIDFORMAT);
190 static fte_t
191 irc_isnickfirst(const int c) {
192 return(isalpha(c) || (c == '[') || (c == ']') || (c == '\\') || (c == '`') || (c == '^') || (c == '{') || (c == '}'));
195 static fte_t
196 irc_isnick(const int c) {
197 return(irc_isnickfirst(c) || isdigit(c) || (c == '-'));
200 static char *irc_html_to_irc(const char *const string) {
201 return string;
203 static char *output = NULL;
204 int o = 0;
205 size_t l,i=0;
207 l = strlen(string);
209 output = realloc(output, (l * 4) + 1);
210 if (output == NULL)
211 abort();
213 while (i < l) {
214 assert(o < ((l * 4) + 1));
215 switch(string[i]) {
216 case '&':
217 if (!strncasecmp(&string[i],"&amp;",5)) {
218 output[o++] = '&';
219 i += 5;
220 } else if (!strncasecmp(&string[i],"&gt;",4)) {
221 output[o++] = '>';
222 i += 4;
223 } else if (!strncasecmp(&string[i],"&lt;",4)) {
224 output[o++] = '<';
225 i += 4;
226 } else if (!strncasecmp(&string[i],"&nbsp;",6)) {
227 output[o++] = ' ';
228 i += 6;
229 } else
230 output[o++] = string[i++];
231 break;
232 case '<':
233 if (!strncasecmp(&string[i],"<b>",3)) {
234 output[o++] = (char) 2;
235 i += 3;
236 } else if (!strncasecmp(&string[i],"</b>",4)) {
237 output[o++] = (char) 2;
238 i += 4;
239 } else if (!strncasecmp(&string[i],"<i>",3)) {
240 output[o++] = (char) 22;
241 i += 3;
242 } else if (!strncasecmp(&string[i],"</i>",4)) {
243 output[o++] = (char) 22;
244 i += 4;
245 } else if (!strncasecmp(&string[i],"<u>",3)) {
246 output[o++] = (char) 31;
247 i += 3;
248 } else if (!strncasecmp(&string[i],"</u>",4)) {
249 output[o++] = (char) 31;
250 i += 4;
251 } else if (!strncasecmp(&string[i],"<br>",4)) {
252 output[o++] = '\020';
253 output[o++] = 'r';
254 output[o++] = '\020';
255 output[o++] = 'n';
256 i += 4;
257 } else
258 output[o++] = string[i++];
259 break;
260 case '\r':
261 output[o++] = '\020';
262 output[o++] = 'r';
263 i++;
264 break;
265 case '\n':
266 output[o++] = '\020';
267 output[o++] = 'n';
268 i++;
269 break;
270 case '\020':
271 output[o++] = '\020';
272 output[o++] = '\020';
273 i++;
274 break;
275 default:
276 output[o++] = string[i++];
277 break;
280 assert(o <= ((l * 4) + 1));
281 output[o] = '\0';
282 return(output);
286 static const char *mIRCar[] = {
287 "#FFFFFF", // 0 white
288 "#000000", // 1 black
289 "#0000FF", // 2 blue (navy)
290 "#00FF00", // 3 green
291 "#FF0000", // 4 red
292 "#4E2F2F", // 5 brown (maroon)
293 "#AA00FF", // 6 purple
294 "#FF7700", // 7 orange (olive)
295 "#FFFF00", // 8 yellow
296 "#32CD32", // 9 lt.green (lime)
297 "#349F79", // 10 teal (a kinda green/blue cyan)
298 "#70DB93", // 11 lt.cyan (cyan ?) (aqua)
299 "#3333FF", // 12 lt.blue (royal)
300 "#FF00AA", // 13 pink (light purple) (fuchsia)
301 "#A8A8A8", // 14 grey
302 "#E6E8FA" // 15 lt.grey (silver)
305 static const char *ANSIar[] = {
306 "#000000", // 30 black
307 "#FF0000", // 31 red
308 "#00FF00", // 32 green
309 "#FFFF00", // 33 yellow
310 "#0000FF", // 34 blue
311 "#FF00FF", // 35 magenta (purple)
312 "#00FFFF", // 36 cyan (aqua)
313 "#FFFFFF", // 37 white
316 static const char *irc_mIRC_to_html(const char *const string, size_t *pos) {
317 int i, col = 0;
319 for (i = 0; (i < 2) && isdigit(string[*pos]); i++, (*pos)++) {
320 col *= 10;
321 col += string[*pos] - '0';
323 if (string[*pos] == ',') {
324 (*pos)++;
325 for (i = 0; (i < 2) && isdigit(string[*pos]); i++, (*pos)++)
328 if ((col >= 0) && (col <= 15))
329 return(mIRCar[col]);
330 else
331 return("#000000");
334 static char *irc_irc_to_html(const char *const string) {
335 return string;
337 static char *output = NULL;
338 int o = 0;
339 size_t l, i = 0, s;
340 int infont = 0, inbold = 0, initalics = 0, inunderline = 0;
342 assert(string != NULL);
344 l = strlen(string);
346 s = l*(sizeof("<font color=\"#RRGGBB\">")-1) + 1;
347 output = realloc(output, s);
348 if (output == NULL)
349 abort();
351 while (i < l) {
352 switch(string[i]) {
353 case 2:
354 if (inbold == 1) {
355 memcpy(&output[o],"</B>",4);
356 o += 4;
357 inbold = 0;
358 } else {
359 memcpy(&output[o],"<B>",3);
360 o += 3;
361 inbold = 1;
363 break;
364 case 3:
365 if (isdigit(string[i+1])) {
366 i++;
367 sprintf(output+o, "<font color=\"%s\">", irc_mIRC_to_html(string, &i));
368 o += sizeof("<font color=\"#RRGGBB\">")-1;
369 infont = 1;
370 i--;
371 } else if (infont == 1) {
372 strcpy(output+o, "</font>");
373 o += sizeof("</font>")-1;
374 infont = 0;
376 break;
377 case 15:
378 if (infont == 1) {
379 strcpy(output+o, "</font>");
380 o += sizeof("</font>")-1;
381 infont = 0;
383 if (inbold == 1) {
384 strcpy(output+o, "</B>");
385 o += sizeof("</B>")-1;
386 inbold = 0;
388 if (initalics == 1) {
389 strcpy(output+o, "</I>");
390 o += sizeof("</I>")-1;
391 initalics = 0;
393 if (inunderline == 1) {
394 strcpy(output+o, "</U>");
395 o += sizeof("</U>")-1;
396 inunderline = 0;
398 break;
399 case 27:
400 if (string[i+1] == '[') {
401 i += 2;
402 while ((string[i] != 0) && (string[i] != 'm')) {
403 int num = 0;
405 if (!isdigit(string[i]))
406 break;
407 while (isdigit(string[i])) {
408 num *= 10;
409 num += string[i] - '0';
410 i++;
412 if (string[i] == ';')
413 i++;
414 switch (num) {
415 case 0:
416 if (infont == 1) {
417 strcpy(output+o, "</font>");
418 o += sizeof("</font>")-1;
419 infont = 0;
421 if (inbold == 1) {
422 strcpy(output+o, "</B>");
423 o += sizeof("</B>")-1;
424 inbold = 0;
426 if (initalics == 1) {
427 strcpy(output+o, "</I>");
428 o += sizeof("</I>")-1;
429 initalics = 0;
431 if (inunderline == 1) {
432 strcpy(output+o, "</U>");
433 o += sizeof("</U>")-1;
434 inunderline = 0;
436 break;
437 case 1:
438 if (inbold == 0) {
439 strcpy(output+o, "<B>");
440 o += sizeof("<B>")-1;
441 inbold = 1;
443 break;
444 case 2:
445 if (inbold == 1) {
446 strcpy(output+o, "</B>");
447 o += sizeof("</B>")-1;
448 inbold = 0;
450 break;
451 case 3:
452 if (inunderline == 0) {
453 strcpy(output+o, "<U>");
454 o += sizeof("<U>")-1;
455 inunderline = 1;
457 break;
458 case 7:
459 if (initalics == 0) {
460 strcpy(output+o, "<I>");
461 o += sizeof("<I>")-1;
462 initalics = 1;
464 break;
465 case 30: case 31: case 32: case 33:
466 case 34: case 35: case 36: case 37:
467 sprintf(output+o, "<font color=\"%s\">", ANSIar[num-30]);
468 o += sizeof("<font color=\"#RRGGBB\">")-1;
469 infont = 1;
470 break;
473 if (string[i] == 0)
474 i--;
476 break;
477 case 22:
478 if (initalics == 1) {
479 memcpy(&output[o],"</I>",4);
480 o += 4;
481 initalics = 0;
482 } else {
483 memcpy(&output[o],"<I>",3);
484 o += 3;
485 initalics = 1;
487 break;
488 case 31:
489 if (inunderline == 1) {
490 memcpy(&output[o],"</U>",4);
491 o += 4;
492 inunderline = 0;
493 } else {
494 memcpy(&output[o],"<U>",3);
495 o += 3;
496 inunderline = 1;
498 break;
499 case '&':
500 memcpy(&output[o],"&amp;",5);
501 o += 5;
502 break;
503 case '<':
504 memcpy(&output[o],"&lt;",4);
505 o += 4;
506 break;
507 case '>':
508 memcpy(&output[o],"&gt;",4);
509 o += 4;
510 break;
511 case 16:
512 switch(string[++i]) {
513 case 16:
514 output[o++] = '\020';
515 break;
516 case 'r':
517 if (string[i+1] == '\020' && string[i+2] == 'n') {
518 i += 2;
519 memcpy(&output[o],"<br>",4);
520 o += 4;
521 } else
522 output[o++] = '\r';
523 break;
524 case 'n':
525 output[o++] = '\n';
526 break;
527 default:
528 output[o++] = string[i];
529 break;
531 break;
532 case ' ':
533 if (string[i+1] == ' ') {
534 memcpy(&output[o], "&nbsp;", 6);
535 o += 6;
536 break;
538 default:
539 output[o++] = string[i];
540 break;
542 i++;
545 output[o] = '\0';
547 return(output);*/
550 static int irc_internal_disconnect(irc_conn_t *c, const int error) {
551 struct s_irc_whois *whois_iter, *whois_iter2;
553 if (c->nickname != NULL) {
554 free(c->nickname);
555 c->nickname = NULL;
557 if (c->password != NULL) {
558 free(c->password);
559 c->password = NULL;
561 for (whois_iter = c->whois_head; whois_iter != NULL; whois_iter = whois_iter2) {
562 whois_iter2 = whois_iter->next;
563 if (whois_iter->nickname != NULL) {
564 free(whois_iter->nickname);
565 whois_iter->nickname = NULL;
567 if (whois_iter->info != NULL) {
568 free(whois_iter->info);
569 whois_iter->info = NULL;
571 free(whois_iter);
573 c->whois_head = NULL;
575 c->passchange = 0;
576 c->usesilence = 1;
577 c->identified = 0;
579 firetalk_callback_disconnect(c, error);
581 return(FE_SUCCESS);
584 static int irc_send_printf(irc_conn_t *c, const char *const format, ...) {
585 va_list ap;
586 size_t i,
587 datai = 0;
588 char data[513];
590 va_start(ap, format);
591 for (i = 0; format[i] != 0; i++) {
592 if (format[i] == '%') {
593 switch (format[++i]) {
602 case 's': {
603 const char
604 *s = irc_html_to_irc(va_arg(ap, char *));
605 size_t slen = strlen(s);
607 if ((datai+slen) > (sizeof(data)-2-1))
608 return(FE_PACKETSIZE);
609 strcpy(data+datai, s);
610 datai += slen;
611 break;
613 case '%':
614 data[datai++] = '%';
615 break;
617 } else {
618 data[datai++] = format[i];
619 if (datai > (sizeof(data)-2-1))
620 return(FE_PACKETSIZE);
623 va_end(ap);
624 data[datai] = 0;
626 #ifdef DEBUG_ECHO
627 irc_echof(c, "send_printf", "%s", data);
628 #endif
630 strcpy(data+datai, "\r\n");
631 datai += 2;
634 struct s_firetalk_handle
635 *fchandle;
637 fchandle = firetalk_find_handle(c);
638 firetalk_internal_send_data(fchandle, data, datai);
641 return(FE_SUCCESS);
644 static char **irc_recv_parse(irc_conn_t *c, unsigned char *buffer, unsigned short *bufferpos) {
645 static char *args[256];
646 static char data[513];
647 size_t curarg;
648 char *tempchr;
649 char *tempchr2;
651 args[0] = NULL;
653 assert(*bufferpos < sizeof(data));
654 memcpy(data, buffer, *bufferpos);
655 data[*bufferpos] = '\0';
657 tempchr = strchr(data, '\n');
658 if (tempchr == NULL)
659 return(NULL);
660 if ((tempchr > data) && (tempchr[-1] == '\r'))
661 tempchr[-1] = 0;
662 else
663 tempchr[0] = 0;
664 *bufferpos -= (tempchr - data + 1);
665 memmove(buffer, &buffer[tempchr - data + 1], *bufferpos);
667 #ifdef DEBUG_ECHO
668 irc_echof(c, "recv_parse", "%s", data);
669 #endif
671 curarg = 0;
672 tempchr = data;
673 if (*tempchr == ':')
674 tempchr++;
675 else
676 args[curarg++] = ":SERVER";
678 while ((curarg < sizeof(args)/sizeof(*args)) && ((tempchr2 = strchr(tempchr, ' ')) != NULL)) {
679 args[curarg++] = tempchr;
680 *tempchr2 = 0;
681 tempchr = tempchr2 + 1;
682 if (*tempchr == ':') {
683 tempchr++;
684 break;
687 args[curarg++] = tempchr;
688 args[curarg] = NULL;
689 return(args);
692 static char *irc_get_nickname(const char *const hostmask) {
693 static char data[512];
694 char *tempchr;
696 strncpy(data, hostmask, sizeof(data)-1);
697 data[sizeof(data)-1] = 0;
699 if ((tempchr = strchr(data, '!')) != NULL)
700 *tempchr = 0;
701 return(data);
704 static fte_t
705 irc_set_nickname(irc_conn_t *c, const char *const nickname) {
706 return(irc_send_printf(c,"NICK %s",nickname));
709 static fte_t
710 irc_set_password(irc_conn_t *c, const char *const oldpass, const char *const newpass) {
711 c->passchange++;
712 return(irc_send_printf(c,"PRIVMSG NickServ :SET PASSWORD %s",newpass));
715 static void
716 irc_destroy_handle(irc_conn_t *c) {
717 irc_send_printf(c,"QUIT :Handle destroyed");
718 irc_internal_disconnect(c,FE_USERDISCONNECT);
719 free(c);
722 static fte_t
723 irc_disconnect(irc_conn_t *c) {
724 irc_send_printf(c,"QUIT :User disconnected");
725 return(irc_internal_disconnect(c,FE_USERDISCONNECT));
728 static irc_conn_t
729 *irc_create_handle(void) {
730 irc_conn_t *c;
732 c = calloc(1, sizeof(*c));
733 if (c == NULL)
734 abort();
735 c->usesilence = 1;
737 return(c);
740 #if defined(HAVE_GETPWUID) && defined(HAVE_GETUID)
741 # include <pwd.h>
742 #endif
744 static fte_t
745 irc_signon(irc_conn_t *c, const char *const nickname) {
747 char pass[129];
748 *pass=0;
750 firetalk_callback_needpass(c, pass, sizeof(pass));
752 if(strlen(pass))
753 if(irc_send_printf(c, "PASS %s", pass) != FE_SUCCESS)
754 return FE_PACKET;
756 #if defined(HAVE_GETPWUID) && defined(HAVE_GETUID)
757 struct passwd *pw = getpwuid(getuid());
758 char buf[1024];
759 int i;
761 for (i = 0; (pw->pw_gecos[i] != 0) && (pw->pw_gecos[i] != ',') && (i < sizeof(buf)-1); i++)
762 buf[i] = pw->pw_gecos[i];
763 if (i == 0) {
764 snprintf(buf, sizeof(buf), "http://www.centerim.org user");
765 i = strlen(buf);
767 buf[i] = 0;
769 if (irc_send_printf(c, "USER %s %s %s :%s", pw->pw_name, nickname, nickname, buf) != FE_SUCCESS)
770 return(FE_PACKET);
771 #else
772 if (irc_send_printf(c, "USER %s %s %s :%s", nickname, nickname, nickname, nickname) != FE_SUCCESS)
773 return(FE_PACKET);
774 #endif
776 if (irc_send_printf(c, "NICK %s", nickname) != FE_SUCCESS)
777 return(FE_PACKET);
779 free(c->nickname);
780 c->nickname = strdup(nickname);
781 if (c->nickname == NULL)
782 abort();
784 return(FE_SUCCESS);
787 static fte_t
788 irc_preselect(irc_conn_t *c, fd_set *read, fd_set *write, fd_set *except, int *n) {
789 return(FE_SUCCESS);
792 static fte_t
793 irc_postselect(irc_conn_t *c, fd_set *read, fd_set *write, fd_set *except) {
794 return(FE_SUCCESS);
797 static void irc_addwhois(irc_conn_t *c, const char *const name, const char *const format, ...) {
798 struct s_irc_whois *whoisiter;
799 char buf[1024];
800 va_list msg;
802 va_start(msg, format);
803 vsnprintf(buf, sizeof(buf), format, msg);
804 va_end(msg);
806 for (whoisiter = c->whois_head; whoisiter != NULL; whoisiter = whoisiter->next)
807 if (irc_compare_nicks(name, whoisiter->nickname) == 0) {
808 int len = whoisiter->info?strlen(whoisiter->info):0;
810 whoisiter->info = realloc(whoisiter->info, len+strlen(buf)+1);
811 if (whoisiter->info == NULL)
812 abort();
813 strcpy(whoisiter->info+len, buf);
814 break;
818 static fte_t irc_got_data_parse(irc_conn_t *c, char **args) {
819 struct s_irc_whois
820 *whoisiter,
821 *whoisiter2;
822 char *tempchr;
825 static unsigned int inwhois = 0;
826 int handled = 0,
827 numeric;
829 handled = 1;
830 if (strcmp(args[1], "PING") == 0) {
831 if (args[2] != NULL) {
832 if (irc_send_printf(c, "PONG :%s", args[2]) != 0) {
833 irc_internal_disconnect(c, FE_PACKET);
834 return(FE_PACKET);
836 } else {
837 if (irc_send_printf(c, "PONG") != 0) {
838 irc_internal_disconnect(c, FE_PACKET);
839 return(FE_PACKET);
842 } else if (strcmp(args[1], "QUIT") == 0) {
843 const char *name = irc_get_nickname(args[0]);
845 firetalk_callback_im_buddyonline(c, name, 0);
846 if (irc_compare_nicks(c->nickname, name) == 0)
847 irc_internal_disconnect(c, FE_DISCONNECT);
848 else
849 firetalk_callback_chat_user_quit(c, name, irc_irc_to_html(args[2]));
850 } else
851 handled = 0;
853 if (handled)
854 return(FE_SUCCESS);
856 numeric = atoi(args[1]);
858 if (args[2] == NULL)
859 goto unhandled;
861 handled = 1;
862 if (strcmp(args[1], "JOIN") == 0) {
863 const char *name = irc_get_nickname(args[0]);
865 firetalk_callback_im_buddyonline(c, name, 1);
866 if (irc_compare_nicks(c->nickname, name) == 0) {
867 firetalk_callback_chat_joined(c, args[2]);
869 if (c->identified == 1) {
870 if (irc_send_printf(c, "PRIVMSG ChanServ :OP %s %s", args[2], c->nickname) != FE_SUCCESS) {
871 irc_internal_disconnect(c, FE_PACKET);
872 return(FE_PACKET);
875 } else {
876 char *extra = strchr(args[0], '!');
878 firetalk_callback_chat_user_joined(c, args[2], name, (extra != NULL)?(extra+1):NULL);
880 } else if (strcmp(args[1], "PART") == 0) {
881 const char *name = irc_get_nickname(args[0]);
883 if (irc_compare_nicks(c->nickname, name) == 0) {
884 irc_disc_rem(c, args[2]);
885 firetalk_callback_chat_left(c, args[2]);
886 } else {
887 irc_disc_user_rem(c, args[2], name);
888 firetalk_callback_chat_user_left(c, args[2], name, (args[3] != NULL)?irc_irc_to_html(args[3]):NULL);
890 } else if (strcmp(args[1],"NICK") == 0) {
891 const char *name = irc_get_nickname(args[0]);
893 if (irc_compare_nicks(c->nickname, name) == 0) {
894 free(c->nickname);
895 c->nickname = strdup(args[2]);
896 if (c->nickname == NULL)
897 abort();
898 firetalk_callback_newnick(c, c->nickname);
900 firetalk_callback_user_nickchanged(c, name, args[2]);
901 } else
902 handled = 0;
904 if (handled)
905 return(FE_SUCCESS);
907 if (args[3] == NULL)
908 goto unhandled;
910 handled = 1;
911 if (strcmp(args[1],"PRIVMSG") == 0) {
912 /* scan for CTCPs */
913 while ((tempchr = strchr(args[3], 1))) {
914 char *sp;
916 if ((sp = strchr(tempchr+1, 1))) {
917 *sp = 0;
919 /* we have a ctcp */
920 if (strchr(ROOMSTARTS, args[2][0])) {
921 /* chat room subcode */
922 if (strncasecmp(&tempchr[1],"ACTION ",7) == 0)
923 firetalk_callback_chat_getaction(c, args[2], irc_get_nickname(args[0]), 0, irc_irc_to_html(tempchr+8));
924 } else {
925 char *endcommand;
927 endcommand = strchr(&tempchr[1], ' ');
928 if (endcommand) {
929 *endcommand = '\0';
930 endcommand++;
931 firetalk_callback_subcode_request(c, irc_get_nickname(args[0]), &tempchr[1], endcommand);
932 } else
933 firetalk_callback_subcode_request(c, irc_get_nickname(args[0]), &tempchr[1], NULL);
935 memmove(tempchr, sp+1, strlen(sp+1) + 1);
936 } else
937 break;
939 if (args[3][0] != '\0') {
940 if (strchr(ROOMSTARTS, args[2][0]))
941 firetalk_callback_chat_getmessage(c, args[2], irc_get_nickname(args[0]), 0, irc_irc_to_html(args[3]));
942 else
943 firetalk_callback_im_getmessage(c, irc_get_nickname(args[0]), 0, irc_irc_to_html(args[3]));
945 } else if (strcmp(args[1],"NOTICE") == 0) {
946 const char *name = irc_get_nickname(args[0]);
948 /* scan for CTCP's */
949 while ((tempchr = strchr(args[3], 1))) {
950 char *sp;
952 if ((sp = strchr(tempchr+1, 1)))
953 *sp = 0;
954 /* we have a ctcp */
955 if (strchr(ROOMSTARTS, args[2][0]) == NULL) {
956 char *endcommand;
957 endcommand = strchr(&tempchr[1], ' ');
958 if (endcommand) {
959 *endcommand = '\0';
960 endcommand++;
961 firetalk_callback_subcode_reply(c, name, &tempchr[1], endcommand);
962 } else
963 firetalk_callback_subcode_reply(c, name, &tempchr[1], NULL);
965 if (sp)
966 memcpy(tempchr, sp+1, strlen(sp+1) + 1);
967 else
968 break;
970 if (strcasecmp(name, "NickServ") == 0) {
971 if ((strstr(args[3],"IDENTIFY") != NULL) && (strstr(args[3],"/msg") != NULL) && (strstr(args[3],"HELP") == NULL)) {
972 c->identified = 0;
973 /* nickserv seems to be asking us to identify ourselves, and we have a password */
974 if (!c->password) {
975 c->password = calloc(1, 128);
976 if (c->password == NULL)
977 abort();
978 firetalk_callback_needpass(c,c->password,128);
980 if ((c->password != NULL) && irc_send_printf(c,"PRIVMSG NickServ :IDENTIFY %s",c->password) != 0) {
981 irc_internal_disconnect(c,FE_PACKET);
982 return(FE_PACKET);
984 } else if ((strstr(args[3],"Password changed") != NULL) && (c->passchange != 0)) {
985 /* successful change */
986 c->passchange--;
987 firetalk_callback_passchanged(c);
988 } else if ((strstr(args[3],"authentication required") != NULL) && (c->passchange != 0)) {
989 /* didn't log in with the right password initially, not happening */
990 c->identified = 0;
991 c->passchange--;
992 firetalk_callback_error(c,FE_NOCHANGEPASS,NULL,args[3]);
993 } else if ((strstr(args[3],"isn't registered") != NULL) && (c->passchange != 0)) {
994 /* nick not registered, fail */
995 c->passchange--;
996 firetalk_callback_error(c,FE_NOCHANGEPASS,NULL,args[3]);
997 } else if (strstr(args[3],"Password accepted") != NULL) {
998 /* we're recognized */
999 c->identified = 1;
1000 if (irc_send_printf(c,"PRIVMSG ChanServ :OP ALL") != FE_SUCCESS) {
1001 irc_internal_disconnect(c,FE_PACKET);
1002 return(FE_PACKET);
1004 } else if (strchr(ROOMSTARTS, args[2][0]))
1005 firetalk_callback_chat_getmessage(c, args[2], name, 1, irc_irc_to_html(args[3]));
1006 else
1007 firetalk_callback_im_getmessage(c, name, 1, irc_irc_to_html(args[3]));
1008 } else if (strchr(name, '.') != NULL) {
1009 if (strncmp(args[3], "*** Notice -- ", sizeof("*** Notice -- ")-1) == 0)
1010 firetalk_callback_chat_getmessage(c, ":RAW", name, 1, irc_irc_to_html(args[3]+sizeof("*** Notice -- ")-1));
1011 else
1012 firetalk_callback_chat_getmessage(c, ":RAW", name, 1, irc_irc_to_html(args[3]));
1013 } else if (args[3][0] != '\0') {
1014 if (strchr(ROOMSTARTS, args[2][0]))
1015 firetalk_callback_chat_getmessage(c, args[2], name, 1, irc_irc_to_html(args[3]));
1016 else
1017 firetalk_callback_im_getmessage(c, name, 1, irc_irc_to_html(args[3]));
1019 } else if (strcmp(args[1], "TOPIC") == 0) {
1020 firetalk_callback_chat_gottopic(c, args[2], irc_irc_to_html(args[3]), irc_get_nickname(args[0]));
1021 } else if (strcmp(args[1], "KICK") == 0) {
1022 const char *name = irc_get_nickname(args[3]);
1024 if (irc_compare_nicks(c->nickname, name) == 0) {
1025 irc_disc_rem(c, args[2]);
1026 firetalk_callback_chat_kicked(c, args[2], irc_get_nickname(args[0]), irc_irc_to_html(args[4]));
1027 } else {
1028 irc_disc_user_rem(c, args[2], name);
1030 tempchr = strdup(name);
1031 if (tempchr == NULL)
1032 abort();
1033 firetalk_callback_chat_user_kicked(c, args[2], tempchr, irc_get_nickname(args[0]), irc_irc_to_html(args[4]));
1034 free(tempchr);
1035 tempchr = NULL;
1037 } else
1038 handled = 0;
1040 if (handled)
1041 return(FE_SUCCESS);
1043 if (numeric == 311) // RPL_WHOISUSER
1044 inwhois = 1;
1045 else if (numeric == 318)// RPL_ENDOFWHOIS
1046 inwhois = 0;
1048 if (!inwhois)
1049 switch (numeric) {
1050 case 333: /* :PREFIX 333 sn channel topicsetuser topicsettime */
1051 case 306: /* :PREFIX 306 sn :You have been marked as being away */
1052 case 305: /* :PREFIX 305 sn :You are no longer marked as being away */
1053 case 396: /* :PREFIX 396 sn whoishost :is now your hidden host */
1054 return(FE_SUCCESS);
1057 handled = 1;
1058 switch (numeric) {
1059 case 366: /* :PREFIX 366 sn channel :End of /NAMES list. */
1060 firetalk_callback_chat_user_joined(c, args[3], NULL, NULL);
1061 break;
1062 case 301: /* RPL_AWAY */
1063 break;
1064 case 313: /* RPL_WHOISOPER */
1065 for (whoisiter = c->whois_head; whoisiter != NULL; whoisiter = whoisiter->next)
1066 if (irc_compare_nicks(args[3],whoisiter->nickname) == 0) {
1067 whoisiter->flags |= FF_ADMIN;
1068 break;
1070 break;
1071 case 318: /* RPL_ENDOFWHOIS */
1072 whoisiter2 = NULL;
1073 for (whoisiter = c->whois_head; whoisiter != NULL; whoisiter = whoisiter->next) {
1074 if (irc_compare_nicks(args[3], whoisiter->nickname) == 0) {
1075 /* manual whois */
1076 firetalk_callback_gotinfo(c, whoisiter->nickname, whoisiter->info, 0, whoisiter->online, whoisiter->idle, whoisiter->flags);
1077 free(whoisiter->nickname);
1078 whoisiter->nickname = NULL;
1079 if (whoisiter->info != NULL) {
1080 free(whoisiter->info);
1081 whoisiter->info = NULL;
1083 if (whoisiter2)
1084 whoisiter2->next = whoisiter->next;
1085 else
1086 c->whois_head = whoisiter->next;
1087 free(whoisiter);
1088 whoisiter = NULL;
1089 break;
1091 whoisiter2 = whoisiter;
1093 break;
1094 case 401: /* ERR_NOSUCHNICK */
1095 firetalk_callback_im_buddyonline(c, args[3], 0);
1096 case 441: /* ERR_USERNOTINCHANNEL */
1097 case 443: /* ERR_USERONCHANNEL */
1098 if (!strcasecmp(args[3], "NickServ") && c->passchange)
1099 c->passchange--;
1100 whoisiter2 = NULL;
1101 for (whoisiter = c->whois_head; whoisiter != NULL; whoisiter = whoisiter->next) {
1102 if (irc_compare_nicks(args[3], whoisiter->nickname) == 0) {
1103 free(whoisiter->nickname);
1104 whoisiter->nickname = NULL;
1105 if (whoisiter->info != NULL) {
1106 free(whoisiter->info);
1107 whoisiter->info = NULL;
1109 if (whoisiter2)
1110 whoisiter2->next = whoisiter->next;
1111 else
1112 c->whois_head = whoisiter->next;
1113 free(whoisiter);
1114 whoisiter = NULL;
1115 firetalk_callback_error(c, FE_BADUSER, args[3], args[4]);
1116 break;
1118 whoisiter2 = whoisiter;
1120 break;
1121 case 403: /* ERR_NOSUCHCHANNEL */
1122 case 442: /* ERR_NOTONCHANNEL */
1123 firetalk_callback_error(c, FE_BADROOM, args[3], args[4]);
1124 break;
1125 case 404: /* ERR_CANNOTSENDTOCHAN */
1126 case 405: /* ERR_TOOMANYCHANNELS */
1127 case 471: /* ERR_CHANNELISFULL */
1128 case 473: /* ERR_INVITEONLYCHAN */
1129 case 474: /* ERR_BANNEDFROMCHAN */
1130 case 475: /* ERR_BADCHANNELKEY */
1131 firetalk_callback_error(c, FE_ROOMUNAVAILABLE, args[3], args[4]);
1132 break;
1133 case 412: /* ERR_NOTEXTTOSEND */
1134 firetalk_callback_error(c, FE_BADMESSAGE, NULL, args[4]);
1135 break;
1136 case 421: /* ERR_UNKNOWNCOMMAND */
1137 if (strcmp(args[3], "SILENCE") == 0)
1138 c->usesilence = 0;
1139 goto unhandled;
1140 break;
1141 case 433: /* ERR_NICKNAMEINUSE */
1142 firetalk_callback_error(c, FE_BADUSER, NULL, "Nickname in use.");
1143 break;
1144 case 482: /* ERR_CHANOPRIVSNEEDED */
1145 firetalk_callback_error(c, FE_NOPERMS, args[3], "You need to be a channel operator.");
1146 break;
1147 default:
1148 handled = 0;
1151 if (handled)
1152 return(FE_SUCCESS);
1154 if (args[4] == NULL)
1155 goto unhandled;
1157 if (strcmp(args[1],"MODE") == 0) {
1158 const char
1159 *source = irc_get_nickname(args[0]);
1160 int loc = 0,
1161 arg = 4,
1162 dir = 1;
1163 #ifdef RAWIRCMODES
1164 int i;
1165 char buf[512];
1167 strcpy(buf, args[3]);
1168 for (i = 4; args[i] != NULL; i++) {
1169 strcat(buf, " ");
1170 strcat(buf, args[i]);
1172 firetalk_callback_chat_modechanged(c, args[2], buf, source);
1173 #endif
1175 while ((args[arg] != NULL) && (args[3][loc] != '\0')) {
1176 switch (args[3][loc++]) {
1177 case '+':
1178 dir = 1;
1179 break;
1180 case '-':
1181 dir = -1;
1182 break;
1183 case 'o':
1184 if (dir == 1) {
1185 firetalk_callback_chat_user_opped(c, args[2], args[arg++], source);
1186 if (irc_compare_nicks(args[arg-1], c->nickname) == FE_SUCCESS)
1187 firetalk_callback_chat_opped(c, args[2], source);
1188 } else if (dir == -1) {
1189 firetalk_callback_chat_user_deopped(c, args[2], args[arg++], source);
1190 if (irc_compare_nicks(args[arg-1], c->nickname) == FE_SUCCESS) {
1191 firetalk_callback_chat_deopped(c, args[2], source);
1192 if (c->identified == 1) {
1193 /* this is us, and we're identified, so we can request a reop */
1194 if (irc_send_printf(c,"PRIVMSG ChanServ :OP %s %s",args[2],c->nickname) != FE_SUCCESS) {
1195 irc_internal_disconnect(c,FE_PACKET);
1196 return(FE_PACKET);
1201 break;
1202 case 'k':
1203 if (dir == 1)
1204 firetalk_callback_chat_keychanged(c, args[2], args[arg], source);
1205 else
1206 firetalk_callback_chat_keychanged(c, args[2], NULL, source);
1207 arg++;
1208 break;
1209 case 'v':
1210 case 'b':
1211 case 'l':
1212 arg++;
1213 break;
1214 default:
1215 break;
1218 return(FE_SUCCESS);
1221 handled = 1;
1222 switch (numeric) {
1223 case 317: /* RPL_WHOISIDLE */
1224 for (whoisiter = c->whois_head; whoisiter != NULL; whoisiter = whoisiter->next)
1225 if (irc_compare_nicks(args[3], whoisiter->nickname) == 0) {
1226 whoisiter->online = atol(args[5]);
1227 whoisiter->idle = atol(args[4])/60;
1229 break;
1230 case 312: /* RPL_WHOISSERVER */
1231 irc_addwhois(c, args[3], "<br>On server %s (%s)", args[4], irc_irc_to_html(args[5]));
1232 break;
1233 case 319: /* RPL_WHOISCHANNELS */
1234 irc_addwhois(c, args[3], "<br>On channels %s", irc_irc_to_html(args[4]));
1235 break;
1236 case 332: /* RPL_TOPIC */
1237 firetalk_callback_chat_gottopic(c, args[3], irc_irc_to_html(args[4]), NULL);
1238 break;
1239 default:
1240 handled = 0;
1243 if (handled)
1244 return(FE_SUCCESS);
1246 if (args[5] == NULL)
1247 goto unhandled;
1249 if (numeric == 353) { /* RPL_NAMREPLY */
1250 char *str = args[5];
1252 while ((str != NULL) && (*str != 0)) {
1253 int oped = 0,
1254 voiced = 0;
1255 char *sp;
1257 if ((sp = strchr(str, ' ')) != NULL)
1258 *sp = 0;
1260 while ((*str != 0) && !irc_isnickfirst(*str)) {
1261 if (*str == '@')
1262 oped = 1;
1263 else if (*str == '+')
1264 voiced = 1;
1265 str++;
1268 firetalk_callback_chat_user_joined(c, args[4], str, NULL);
1269 firetalk_callback_im_buddyonline(c, str, 1);
1270 if (oped) {
1271 firetalk_callback_chat_user_opped(c, args[4], str, NULL);
1272 if (irc_compare_nicks(str, c->nickname) == FE_SUCCESS)
1273 firetalk_callback_chat_opped(c, args[4], NULL);
1276 if (sp != NULL)
1277 str = sp+1;
1278 else
1279 str = NULL;
1281 return(FE_SUCCESS);
1284 if ((args[6] == NULL) || (args[7] == NULL))
1285 goto unhandled;
1287 if (numeric == 311) { /* RPL_WHOISUSER */
1288 char *gecos = irc_irc_to_html(args[7]);
1289 int i;
1291 for (i = 0; gecos[i] != 0; i++)
1292 if (strncasecmp(gecos+i, "<HTML>", sizeof("<HTML>")-1) == 0)
1293 break;
1294 if (gecos[i] != 0)
1295 irc_addwhois(c, args[3], "%s@%s (%s)", args[4], args[5], firetalk_htmlentities(gecos));
1296 else
1297 irc_addwhois(c, args[3], "%s@%s (<HTML>%s</HTML>)", args[4], args[5], gecos);
1298 return(FE_SUCCESS);
1299 } else if (numeric == 352) { /* WHO output */
1300 char buf[1024], buf2[1024];
1301 int i;
1303 snprintf(buf, sizeof(buf), "%s %s %s %s", args[7], args[4], args[5], args[6]);
1304 for (i = 8; args[i] != NULL; i++)
1306 snprintf(buf2, sizeof(buf2), ", %s", args[i]);
1307 strncat(buf, buf2, sizeof(buf)-strlen(buf)-1);
1309 firetalk_callback_chat_getmessage(c, ":RAW", args[3], 0, buf);
1310 return(FE_SUCCESS);
1313 unhandled:
1314 if (inwhois) {
1315 char buf[1024];
1316 int i;
1318 snprintf(buf, sizeof(buf), "<br>%s", args[3]);
1319 for (i = numeric?4:3; args[i+1] != NULL; i++)
1321 snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), " %s", args[i]);
1322 for (i = numeric?4:3; args[i+1] != NULL; i++)
1323 snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), " %s", args[i]);
1324 snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), " (%s)", args[1]);
1325 irc_addwhois(c, args[3], "%s", buf);
1326 } else {
1327 char buf[1024], buf2[1024];
1328 int i;
1330 *buf = 0;
1331 for (i = 1; args[i+1] != NULL; i++)
1333 snprintf(buf2, sizeof(buf2), "<B>%s</B>, ", args[i]);
1334 strncat(buf, buf2, sizeof(buf)-strlen(buf)-1);
1336 strncat(buf, args[i], sizeof(buf)-strlen(buf)-1);
1337 firetalk_callback_chat_getmessage(c, ":RAW", irc_get_nickname(args[0]), 0, buf);
1341 return(FE_SUCCESS);
1344 static fte_t
1345 irc_got_data(irc_conn_t *c, unsigned char *buffer, unsigned short *bufferpos) {
1346 char **args;
1348 while (((args = irc_recv_parse(c, buffer, bufferpos)) != NULL) && (args[1] != NULL)) {
1349 fte_t fte;
1351 if ((fte = irc_got_data_parse(c, args)) != FE_SUCCESS)
1352 return(fte);
1355 return(FE_SUCCESS);
1358 static fte_t
1359 irc_got_data_connecting(irc_conn_t *c, unsigned char *buffer, unsigned short *bufferpos) {
1360 char **args;
1362 while (((args = irc_recv_parse(c, buffer, bufferpos)) != NULL) && (args[1] != NULL)) {
1363 if (strcmp(args[1], "ERROR") == 0) {
1364 irc_send_printf(c,"QUIT :error");
1365 if (args[2] == NULL)
1366 firetalk_callback_connectfailed(c, FE_PACKET, "Server returned ERROR");
1367 else
1368 firetalk_callback_connectfailed(c, FE_PACKET, args[2]);
1369 return(FE_PACKET);
1370 } else {
1371 switch (atoi(args[1])) {
1372 case 1: /* :PREFIX 001 sn :Welcome message */
1373 if (strcmp(c->nickname, args[2]) != 0) {
1374 firetalk_callback_user_nickchanged(c, c->nickname, args[2]);
1375 free(c->nickname);
1376 c->nickname = strdup(args[2]);
1377 if (c->nickname == NULL)
1378 abort();
1379 firetalk_callback_newnick(c, args[2]);
1381 break;
1382 case 376: /* End of MOTD */
1383 case 422: /* MOTD is missing */
1384 firetalk_callback_doinit(c,c->nickname);
1385 firetalk_callback_connected(c);
1386 break;
1387 case 431:
1388 case 432:
1389 case 436:
1390 case 461:
1391 irc_send_printf(c,"QUIT :Invalid nickname");
1392 firetalk_callback_connectfailed(c,FE_BADUSER,"Invalid nickname");
1393 return(FE_BADUSER);
1394 case 433:
1395 irc_send_printf(c,"QUIT :Invalid nickname");
1396 firetalk_callback_connectfailed(c,FE_BADUSER,"Nickname in use");
1397 return(FE_BADUSER);
1398 case 465:
1399 irc_send_printf(c,"QUIT :banned");
1400 firetalk_callback_connectfailed(c,FE_BLOCKED,"You are banned");
1401 return(FE_BLOCKED);
1402 default: {
1403 fte_t fte;
1405 if ((fte = irc_got_data_parse(c, args)) != FE_SUCCESS)
1406 return(fte);
1407 break;
1413 return(FE_SUCCESS);
1416 static fte_t irc_chat_join(irc_conn_t *c, const char *const room) {
1417 return(irc_send_printf(c,"JOIN %s",room));
1420 static fte_t irc_chat_part(irc_conn_t *c, const char *const room) {
1421 return(irc_send_printf(c,"PART %s",room));
1424 static fte_t irc_chat_send_message(irc_conn_t *c, const char *const room, const char *const message, const int auto_flag) {
1425 if (strcasecmp(room, ":RAW") == 0)
1426 return(irc_send_printf(c, "%s", message));
1428 #ifdef DEBUG_ECHO
1429 irc_echof(c, "chat_send_message", "c=%#p, room=%#p \"%s\", message=%#p \"%s\", auto_flag=%i\n", c, room, room, message, message, auto_flag);
1430 #endif
1432 if (auto_flag)
1433 return(irc_send_printf(c, "NOTICE %s :%s", room, message));
1434 else
1435 return(irc_send_printf(c, "PRIVMSG %s :%s", room, message));
1438 static fte_t irc_chat_send_action(irc_conn_t *c, const char *const room, const char *const message, const int auto_flag) {
1439 return(irc_send_printf(c,"PRIVMSG %s :\001ACTION %s\001",room,message));
1442 static fte_t irc_chat_invite(irc_conn_t *c, const char *const room, const char *const who, const char *const message) {
1443 return(irc_send_printf(c,"INVITE %s %s",who,room));
1446 static fte_t irc_im_send_message(irc_conn_t *c, const char *const dest, const char *const message, const int auto_flag) {
1447 struct s_firetalk_handle *fchandle;
1448 char buf[512+1];
1450 if (strcasecmp(dest, ":RAW") == 0)
1451 return(irc_send_printf(c, "%s", message));
1453 fchandle = firetalk_find_handle(c);
1454 if (auto_flag) {
1455 snprintf(buf, sizeof(buf), "NOTICE %s :%s", dest, message);
1456 firetalk_queue_append(buf, sizeof(buf), &(fchandle->subcode_replies), dest);
1457 } else {
1458 snprintf(buf, sizeof(buf), "PRIVMSG %s :%s", dest, message);
1459 firetalk_queue_append(buf, sizeof(buf), &(fchandle->subcode_requests), dest);
1461 return(irc_send_printf(c, "%s", buf));
1464 static fte_t irc_im_send_action(irc_conn_t *c, const char *const dest, const char *const message, const int auto_flag) {
1465 return(irc_send_printf(c, "PRIVMSG %s :\001ACTION %s\001", dest, message));
1468 static fte_t irc_chat_set_topic(irc_conn_t *c, const char *const room, const char *const topic) {
1469 return(irc_send_printf(c,"TOPIC %s :%s",room,topic));
1472 static fte_t irc_chat_op(irc_conn_t *c, const char *const room, const char *const who) {
1473 return(irc_send_printf(c,"MODE %s +o %s",room,who));
1476 static fte_t irc_chat_deop(irc_conn_t *c, const char *const room, const char *const who) {
1477 return(irc_send_printf(c,"MODE %s -o %s",room,who));
1480 static fte_t irc_chat_kick(irc_conn_t *c, const char *const room, const char *const who, const char *const reason) {
1481 if (reason)
1482 return(irc_send_printf(c,"KICK %s %s :%s",room,who,reason));
1483 else
1484 return(irc_send_printf(c,"KICK %s %s",room,who));
1487 static fte_t irc_chat_requestextended(client_t c, const char * const room) {
1488 return (irc_send_printf(c,"WHO %s", room));
1491 static fte_t irc_im_add_buddy(irc_conn_t *c, const char *const name, const char *const group, const char *const friendly) {
1492 struct s_firetalk_handle *fchandle;
1494 fchandle = firetalk_find_handle(c);
1496 if (firetalk_user_visible(fchandle, name) == FE_SUCCESS)
1497 firetalk_callback_im_buddyonline(c, name, 1);
1498 return(FE_SUCCESS);
1501 static fte_t irc_im_remove_buddy(irc_conn_t *c, const char *const name, const char *const group) {
1502 firetalk_callback_im_buddyonline(c, name, 0);
1504 return(FE_SUCCESS);
1507 static fte_t irc_im_add_deny(irc_conn_t *c, const char *const nickname) {
1508 if (c->usesilence == 1)
1509 return(irc_send_printf(c,"SILENCE +%s!*@*",nickname));
1510 else
1511 return(FE_SUCCESS);
1514 static fte_t irc_im_remove_deny(irc_conn_t *c, const char *const nickname) {
1515 if (c->usesilence == 1)
1516 return(irc_send_printf(c,"SILENCE -%s!*@*",nickname));
1517 else
1518 return(FE_SUCCESS);
1521 static fte_t irc_im_upload_buddies(irc_conn_t *c) {
1522 return(FE_SUCCESS);
1525 static fte_t irc_im_upload_denies(irc_conn_t *c) {
1526 return(FE_SUCCESS);
1529 static fte_t irc_im_evil(irc_conn_t *c, const char *const who) {
1530 return(FE_SUCCESS);
1533 static fte_t irc_set_privacy(client_t c, const char *const mode) {
1534 return(FE_SUCCESS);
1537 static fte_t irc_get_info(irc_conn_t *c, const char *const nickname) {
1538 struct s_irc_whois *whoistemp;
1540 whoistemp = c->whois_head;
1541 c->whois_head = calloc(1, sizeof(struct s_irc_whois));
1542 if (c->whois_head == NULL)
1543 abort();
1544 c->whois_head->nickname = strdup(nickname);
1545 if (c->whois_head->nickname == NULL)
1546 abort();
1547 c->whois_head->flags = 0;
1548 c->whois_head->online = 0;
1549 c->whois_head->idle = 0;
1550 c->whois_head->info = NULL;
1551 c->whois_head->next = whoistemp;
1552 return(irc_send_printf(c, "WHOIS %s", nickname));
1555 static fte_t
1556 irc_set_info(irc_conn_t *c, const char *const info) {
1557 return(FE_SUCCESS);
1560 static fte_t
1561 irc_set_away(irc_conn_t *c, const char *const message, const int auto_flag) {
1562 if (message)
1563 return(irc_send_printf(c,"AWAY :%s",message));
1564 else
1565 return(irc_send_printf(c,"AWAY"));
1568 static fte_t irc_periodic(struct s_firetalk_handle *const conn) {
1569 return(FE_SUCCESS);
1572 #if 0
1573 static fte_t irc_subcode_send_request(irc_conn_t *c, const char *const to, const char *const command, const char *const args) {
1574 if (args == NULL) {
1575 if (irc_send_printf(c,"PRIVMSG %s :\001%s\001",to,command) != 0) {
1576 irc_internal_disconnect(c,FE_PACKET);
1577 return(FE_PACKET);
1579 } else {
1580 if (irc_send_printf(c,"PRIVMSG %s :\001%s %s\001",to,command,args) != 0) {
1581 irc_internal_disconnect(c,FE_PACKET);
1582 return(FE_PACKET);
1585 return(FE_SUCCESS);
1588 static fte_t irc_subcode_send_reply(irc_conn_t *c, const char *const to, const char *const command, const char *const args) {
1589 if (to == NULL)
1590 return(FE_SUCCESS);
1592 if (args == NULL) {
1593 if (irc_send_printf(c,"NOTICE %s :\001%s\001",to,command) != 0) {
1594 irc_internal_disconnect(c,FE_PACKET);
1595 return(FE_PACKET);
1597 } else {
1598 if (irc_send_printf(c,"NOTICE %s :\001%s %s\001",to,command,args) != 0) {
1599 irc_internal_disconnect(c,FE_PACKET);
1600 return(FE_PACKET);
1603 return(FE_SUCCESS);
1605 #endif
1607 static char *irc_ctcp_encode(irc_conn_t *c, const char *const command, const char *const message) {
1608 char *str;
1610 if (message != NULL) {
1611 str = malloc(1 + strlen(command) + 1 + strlen(message) + 1 + 1);
1612 if (str == NULL)
1613 abort();
1614 sprintf(str, "\001%s %s\001", command, message);
1615 } else {
1616 str = malloc(1 + strlen(command) + 1 + 1);
1617 if (str == NULL)
1618 abort();
1619 sprintf(str, "\001%s\001", command);
1622 return(str);
1625 const firetalk_protocol_t firetalk_protocol_irc = {
1626 strprotocol: "IRC",
1627 default_server: "irc.n.ml.org",
1628 default_port: 6667,
1629 default_buffersize: 1024/2,
1630 periodic: irc_periodic,
1631 preselect: irc_preselect,
1632 postselect: irc_postselect,
1633 got_data: irc_got_data,
1634 got_data_connecting: irc_got_data_connecting,
1635 comparenicks: irc_compare_nicks,
1636 isprintable: irc_isprint,
1637 disconnect: irc_disconnect,
1638 signon: irc_signon,
1639 get_info: irc_get_info,
1640 set_info: irc_set_info,
1641 set_away: irc_set_away,
1642 set_nickname: irc_set_nickname,
1643 set_password: irc_set_password,
1644 im_add_buddy: irc_im_add_buddy,
1645 im_remove_buddy: irc_im_remove_buddy,
1646 im_add_deny: irc_im_add_deny,
1647 im_remove_deny: irc_im_remove_deny,
1648 im_upload_buddies: irc_im_upload_buddies,
1649 im_upload_denies: irc_im_upload_denies,
1650 im_send_message: irc_im_send_message,
1651 im_send_action: irc_im_send_action,
1652 im_evil: irc_im_evil,
1653 chat_join: irc_chat_join,
1654 chat_part: irc_chat_part,
1655 chat_invite: irc_chat_invite,
1656 chat_set_topic: irc_chat_set_topic,
1657 chat_op: irc_chat_op,
1658 chat_deop: irc_chat_deop,
1659 chat_kick: irc_chat_kick,
1660 chat_send_message: irc_chat_send_message,
1661 chat_send_action: irc_chat_send_action,
1662 // subcode_send_request: irc_subcode_send_request,
1663 // subcode_send_reply: irc_subcode_send_reply,
1664 subcode_encode: irc_ctcp_encode,
1665 set_privacy: irc_set_privacy,
1666 room_normalize: irc_normalize_room_name,
1667 create_handle: irc_create_handle,
1668 destroy_handle: irc_destroy_handle,