Updating ChangeLog for 4.22.10
[centerim.git] / firetalk / firetalk.c
blob8b7d19682f1f843845cacb69bc9bad7bef95721d
1 /*
2 firetalk.c - FireTalk wrapper definitions
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 <string.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/types.h>
24 #include <sys/time.h>
25 #include <unistd.h>
26 #include <strings.h>
27 #include <netinet/in.h>
28 #include <sys/socket.h>
29 #include <arpa/inet.h>
30 #include <time.h>
31 #include <sys/stat.h>
32 #include <netdb.h>
33 #include <errno.h>
34 #include <signal.h>
35 #include <fcntl.h>
37 #define FIRETALK
39 #include "firetalk-int.h"
40 #include "firetalk.h"
42 typedef void (*ptrtotoc)(void *, ...);
43 typedef void (*sighandler_t)(int);
45 /* Global variables */
46 fte_t firetalkerror;
47 static struct s_firetalk_handle *handle_head = NULL;
49 static const firetalk_protocol_t **firetalk_protocols = NULL;
50 static int FP_MAX = 0;
52 fte_t firetalk_register_protocol(const firetalk_protocol_t *const proto) {
53 const firetalk_protocol_t **ptr;
55 if (proto == NULL)
56 abort();
58 ptr = realloc(firetalk_protocols, sizeof(*firetalk_protocols)*(FP_MAX+1));
59 if (ptr == NULL)
60 return(FE_UNKNOWN);
61 firetalk_protocols = ptr;
62 firetalk_protocols[FP_MAX++] = proto;
63 return(FE_SUCCESS);
66 static void firetalk_register_default_protocols(void) {
67 extern const firetalk_protocol_t
68 firetalk_protocol_irc,
69 firetalk_protocol_toc2;
71 if (firetalk_register_protocol(&firetalk_protocol_irc) != FE_SUCCESS)
72 abort();
73 if (firetalk_register_protocol(&firetalk_protocol_toc2) != FE_SUCCESS)
74 abort();
77 int firetalk_find_protocol(const char *strprotocol) {
78 static int registered_defaults = 0;
79 int i;
81 if (strprotocol == NULL)
82 abort();
84 for (i = 0; i < FP_MAX; i++)
85 if (strcasecmp(strprotocol, firetalk_protocols[i]->strprotocol) == 0)
86 return(i);
87 if (!registered_defaults) {
88 registered_defaults = 1;
89 firetalk_register_default_protocols();
90 for (i = 0; i < FP_MAX; i++)
91 if (strcasecmp(strprotocol, firetalk_protocols[i]->strprotocol) == 0)
92 return(i);
94 return(-1);
97 /* Internal function definitions */
99 /* firetalk_find_by_toc searches the firetalk handle list for the toc handle passed, and returns the firetalk handle */
100 firetalk_t firetalk_find_handle(client_t c) {
101 struct s_firetalk_handle *iter;
103 for (iter = handle_head; iter != NULL; iter = iter->next)
104 if (iter->handle == c)
105 return(iter);
106 abort();
109 firetalk_t firetalk_find_clientstruct(void *clientstruct) {
110 struct s_firetalk_handle *iter;
112 for (iter = handle_head; iter != NULL; iter = iter->next)
113 if (iter->clientstruct == clientstruct)
114 return(iter);
115 return(NULL);
118 #define DEBUG
120 #ifdef DEBUG
121 # define VERIFYCONN \
122 do { \
123 if (firetalk_check_handle(conn) != FE_SUCCESS) \
124 abort(); \
125 } while(0)
127 static fte_t firetalk_check_handle(firetalk_t c) {
128 struct s_firetalk_handle *iter;
130 for (iter = handle_head; iter != NULL; iter = iter->next)
131 if (iter == c)
132 return(FE_SUCCESS);
133 return(FE_BADHANDLE);
135 #else
136 # define VERIFYCONN \
137 do { \
138 } while(0)
139 #endif
141 static char **firetalk_parse_subcode_args(char *string) {
142 static char *args[256];
143 int i,n;
144 size_t l;
146 l = strlen(string);
147 args[0] = string;
148 n = 1;
149 for (i = 0; (size_t) i < l && n < 255; i++) {
150 if (string[i] == ' ') {
151 string[i++] = '\0';
152 args[n++] = &string[i];
155 args[n] = NULL;
156 return(args);
159 static unsigned char firetalk_debase64_char(const char c) {
160 if ((c >= 'A') && (c <= 'Z'))
161 return((unsigned char)(c - 'A'));
162 if ((c >= 'a') && (c <= 'z'))
163 return((unsigned char)(26 + (c - 'a')));
164 if ((c >= '0') && (c <= '9'))
165 return((unsigned char)(52 + (c - '0')));
166 if (c == '+')
167 return((unsigned char)62);
168 if (c == '/')
169 return((unsigned char)63);
170 return((unsigned char)0);
173 const char *firetalk_debase64(const char *const str) {
174 static unsigned char out[256];
175 int s, o, len = strlen(str);
177 for (o = s = 0; (s <= (len - 3)) && (o < (sizeof(out)-1)); s += 4, o += 3) {
178 out[o] = (firetalk_debase64_char(str[s]) << 2) | (firetalk_debase64_char(str[s+1]) >> 4);
179 out[o+1] = (firetalk_debase64_char(str[s+1]) << 4) | (firetalk_debase64_char(str[s+2]) >> 2);
180 out[o+2] = (firetalk_debase64_char(str[s+2]) << 6) | firetalk_debase64_char(str[s+3]);
182 out[o] = 0;
183 return((char *)out);
187 fte_t firetalk_im_internal_add_deny(firetalk_t conn, const char *const nickname) {
188 struct s_firetalk_deny *iter;
190 VERIFYCONN;
192 for (iter = conn->deny_head; iter != NULL; iter = iter->next)
193 if (firetalk_protocols[conn->protocol]->comparenicks(iter->nickname, nickname) == FE_SUCCESS)
194 break; /* not an error, user is in buddy list */
196 if (iter == NULL) {
197 iter = conn->deny_head;
198 conn->deny_head = calloc(1, sizeof(struct s_firetalk_deny));
199 if (conn->deny_head == NULL)
200 abort();
201 conn->deny_head->next = iter;
202 conn->deny_head->nickname = strdup(nickname);
203 if (conn->deny_head->nickname == NULL)
204 abort();
207 firetalk_callback_im_buddyonline(conn->handle, nickname, 0);
209 return(FE_SUCCESS);
212 #undef FIRETALK_FORK_RESOLV
213 #ifdef FIRETALK_FORK_RESOLV
214 fte_t firetalk_internal_resolve4(const char *const host, struct in_addr *inet4_ip) {
215 int pi[2];
217 if (pipe(pi) != 0)
218 return(FE_NOTFOUND);
220 switch(fork()) {
221 case -1:
222 close(pi[0]);
223 close(pi[1]);
224 return(FE_NOTFOUND);
225 case 0: {
226 struct hostent
227 *he;
229 close(pi[0]);
230 if (((he = gethostbyaddr(host, strlen(host), AF_INET)) != NULL) && (he->h_addr_list != NULL))
231 write(pi[1], he->h_addr_list[0], sizeof(inet4_ip->s_addr));
232 close(pi[1]);
233 _exit(2);
235 default: {
236 struct timeval
238 fd_set readset;
240 FD_ZERO(&readset);
241 FD_SET(pi[0], &readset);
242 close(pi[1]);
243 tv.tv_sec = 5;
244 tv.tv_usec = 0;
245 if ((select(pi[0]+1, &readset, NULL, NULL, &tv) > 0)
246 && FD_ISSET(pi[0], &readset)
247 && (read(pi[0], &(inet4_ip->s_addr), sizeof(inet4_ip->s_addr)) == sizeof(inet4_ip->s_addr))) {
248 close(pi[0]);
249 return(FE_SUCCESS);
251 close(pi[0]);
252 return(FE_NOTFOUND);
256 #else
257 fte_t firetalk_internal_resolve4(const char *const host, struct in_addr *inet4_ip) {
258 struct hostent *he;
260 he = gethostbyname(host);
261 if (he && he->h_addr_list) {
262 memmove(&(inet4_ip->s_addr), he->h_addr_list[0], sizeof(inet4_ip->s_addr));
263 return(FE_SUCCESS);
266 memset(&(inet4_ip->s_addr), 0, sizeof(inet4_ip->s_addr));
268 return(FE_NOTFOUND);
270 #endif
272 struct sockaddr_in *firetalk_internal_remotehost4(client_t c) {
273 struct s_firetalk_handle
274 *conn = firetalk_find_handle(c);
276 return(&(conn->remote_addr));
279 #ifdef _FC_USE_IPV6
280 fte_t firetalk_internal_resolve6(const char *const host, struct in6_addr *inet6_ip) {
281 struct addrinfo *addr = NULL; // xxx generalize this so that we can use this with v6 and v4
282 struct addrinfo hints = {0, PF_INET6, 0, 0, 0, NULL, NULL, NULL};
284 if (getaddrinfo(host, NULL, &hints, &addr) == 0) {
285 struct addrinfo *cur;
287 for (cur = addr; cur != NULL; cur = cur->ai_next)
288 if (cur->ai_family == PF_INET6) {
289 memcpy(&(inet6_ip->s6_addr), ((struct sockaddr_in6 *)cur->ai_addr)->sin6_addr.s6_addr, 16);
290 freeaddrinfo(addr);
291 return(FE_SUCCESS);
295 memset(&(inet6_ip->s6_addr), 0, sizeof(inet6_ip->s6_addr));
297 if (addr != NULL)
298 freeaddrinfo(addr);
300 return(FE_NOTFOUND);
303 struct sockaddr_in6 *firetalk_internal_remotehost6(client_t c) {
304 struct s_firetalk_handle
305 *conn = firetalk_find_handle(c);
307 return(&(conn->remote_addr6));
309 #endif
311 int firetalk_internal_connect_host_addr(const char *const host, const uint16_t port, struct sockaddr_in *inet4
312 #ifdef _FC_USE_IPV6
313 , struct sockaddr_in6 *inet6
314 #endif
316 #ifdef _FC_USE_IPV6
317 if (firetalk_internal_resolve6(host, &(inet6->sin6_addr)) == FE_SUCCESS) {
318 inet6->sin6_port = htons(port);
319 inet6->sin6_family = AF_INET6;
320 } else
321 inet6 = NULL;
322 #endif
323 if (firetalk_internal_resolve4(host, &(inet4->sin_addr)) == FE_SUCCESS) {
324 inet4->sin_port = htons(port);
325 inet4->sin_family = AF_INET;
326 } else
327 inet4 = NULL;
329 return firetalk_internal_connect(inet4
330 #ifdef _FC_USE_IPV6
331 , inet6
332 #endif
336 int firetalk_internal_connect_host(const char *const host, const int port) {
337 struct sockaddr_in myinet4;
338 #ifdef _FC_USE_IPV6
339 struct sockaddr_in6 myinet6;
340 #endif
342 return(firetalk_internal_connect_host_addr(host, port, &myinet4
343 #ifdef _FC_USE_IPV6
344 , &myinet6
345 #endif
349 int firetalk_internal_connect(struct sockaddr_in *inet4_ip
350 #ifdef _FC_USE_IPV6
351 , struct sockaddr_in6 *inet6_ip
352 #endif
354 int s,i;
356 #ifdef _FC_USE_IPV6
357 if (inet6_ip && (inet6_ip->sin6_addr.s6_addr[0] || inet6_ip->sin6_addr.s6_addr[1]
358 || inet6_ip->sin6_addr.s6_addr[2] || inet6_ip->sin6_addr.s6_addr[3]
359 || inet6_ip->sin6_addr.s6_addr[4] || inet6_ip->sin6_addr.s6_addr[5]
360 || inet6_ip->sin6_addr.s6_addr[6] || inet6_ip->sin6_addr.s6_addr[7]
361 || inet6_ip->sin6_addr.s6_addr[8] || inet6_ip->sin6_addr.s6_addr[9]
362 || inet6_ip->sin6_addr.s6_addr[10] || inet6_ip->sin6_addr.s6_addr[11]
363 || inet6_ip->sin6_addr.s6_addr[12] || inet6_ip->sin6_addr.s6_addr[13]
364 || inet6_ip->sin6_addr.s6_addr[14] || inet6_ip->sin6_addr.s6_addr[15])) {
365 h_errno = 0;
366 s = socket(PF_INET6, SOCK_STREAM, 0);
367 if ((s != -1) && (fcntl(s, F_SETFL, O_NONBLOCK) == 0)) {
368 i = connect(s, (const struct sockaddr *)inet6_ip, sizeof(struct sockaddr_in6));
369 if ((i == 0) || (errno == EINPROGRESS))
370 return(s);
373 #endif
375 if (inet4_ip && inet4_ip->sin_addr.s_addr) {
376 h_errno = 0;
377 s = socket(PF_INET, SOCK_STREAM, 0);
378 if ((s != -1) && (fcntl(s, F_SETFL, O_NONBLOCK) == 0)) {
379 i = connect(s, (const struct sockaddr *)inet4_ip, sizeof(struct sockaddr_in));
380 if ((i == 0) || (errno == EINPROGRESS))
381 return(s);
385 firetalkerror = FE_CONNECT;
386 return(-1);
389 enum firetalk_connectstate firetalk_internal_get_connectstate(client_t c) {
390 struct s_firetalk_handle
391 *conn = firetalk_find_handle(c);
393 return(conn->connected);
396 void firetalk_internal_set_connectstate(client_t c, enum firetalk_connectstate fcs) {
397 struct s_firetalk_handle
398 *conn = firetalk_find_handle(c);
400 conn->connected = fcs;
403 void firetalk_internal_send_data(firetalk_t c, const char *const data, const int length) {
404 if (c->connected == FCS_NOTCONNECTED || c->connected == FCS_WAITING_SYNACK)
405 return;
407 if (send(c->fd,data,length,MSG_DONTWAIT|MSG_NOSIGNAL) != length) {
408 /* disconnect client (we probably overran the queue, or the other end is gone) */
409 firetalk_callback_disconnect(c->handle,FE_PACKET);
412 /* request ratelimit info */
413 /* immediate send or queue? */
416 fte_t firetalk_user_visible(firetalk_t conn, const char *const nickname) {
417 struct s_firetalk_room *iter;
419 VERIFYCONN;
421 for (iter = conn->room_head; iter != NULL; iter = iter->next) {
422 struct s_firetalk_member *mem;
424 for (mem = iter->member_head; mem != NULL; mem = mem->next)
425 if (firetalk_protocols[conn->protocol]->comparenicks(mem->nickname, nickname) == FE_SUCCESS)
426 return(FE_SUCCESS);
428 return(FE_NOMATCH);
431 fte_t firetalk_user_visible_but(firetalk_t conn, const char *const room, const char *const nickname) {
432 struct s_firetalk_room *iter;
434 VERIFYCONN;
436 for (iter = conn->room_head; iter != NULL; iter = iter->next) {
437 struct s_firetalk_member *mem;
439 if (firetalk_protocols[conn->protocol]->comparenicks(iter->name, room) == FE_SUCCESS)
440 continue;
441 for (mem = iter->member_head; mem != NULL; mem = mem->next)
442 if (firetalk_protocols[conn->protocol]->comparenicks(mem->nickname, nickname) == FE_SUCCESS)
443 return(FE_SUCCESS);
445 return(FE_NOMATCH);
448 fte_t firetalk_chat_internal_add_room(firetalk_t conn, const char *const name) {
449 struct s_firetalk_room *iter;
451 VERIFYCONN;
453 for (iter = conn->room_head; iter != NULL; iter = iter->next)
454 if (firetalk_protocols[conn->protocol]->comparenicks(iter->name, name) == FE_SUCCESS)
455 return(FE_DUPEROOM); /* not an error, we're already in room */
457 iter = conn->room_head;
458 conn->room_head = calloc(1, sizeof(struct s_firetalk_room));
459 if (conn->room_head == NULL)
460 abort();
461 conn->room_head->next = iter;
462 conn->room_head->name = strdup(name);
463 if (conn->room_head->name == NULL)
464 abort();
466 return(FE_SUCCESS);
469 fte_t firetalk_chat_internal_add_member(firetalk_t conn, const char *const room, const char *const nickname) {
470 struct s_firetalk_room *iter;
471 struct s_firetalk_member *memberiter;
473 VERIFYCONN;
475 for (iter = conn->room_head; iter != NULL; iter = iter->next)
476 if (firetalk_protocols[conn->protocol]->comparenicks(iter->name, room) == FE_SUCCESS)
477 break;
479 if (iter == NULL) /* we don't know about that room */
480 return(FE_NOTFOUND);
482 for (memberiter = iter->member_head; memberiter != NULL; memberiter = memberiter->next)
483 if (firetalk_protocols[conn->protocol]->comparenicks(memberiter->nickname, nickname) == FE_SUCCESS)
484 return(FE_SUCCESS);
486 memberiter = iter->member_head;
487 iter->member_head = calloc(1, sizeof(struct s_firetalk_member));
488 if (iter->member_head == NULL)
489 abort();
490 iter->member_head->next = memberiter;
491 iter->member_head->nickname = strdup(nickname);
492 if (iter->member_head->nickname == NULL)
493 abort();
495 return(FE_SUCCESS);
498 static void firetalk_im_delete_buddy(firetalk_t conn, const char *const nickname) {
499 struct s_firetalk_buddy *iter, *prev;
501 for (prev = NULL, iter = conn->buddy_head; iter != NULL; prev = iter, iter = iter->next) {
502 assert(iter->nickname != NULL);
503 assert(iter->group != NULL);
505 if (firetalk_protocols[conn->protocol]->comparenicks(nickname, iter->nickname) == FE_SUCCESS)
506 break;
508 if (iter == NULL)
509 return;
511 if (prev != NULL)
512 prev->next = iter->next;
513 else
514 conn->buddy_head = iter->next;
515 free(iter->nickname);
516 iter->nickname = NULL;
517 free(iter->group);
518 iter->group = NULL;
519 if (iter->friendly != NULL) {
520 free(iter->friendly);
521 iter->friendly = NULL;
523 if (iter->capabilities != NULL) {
524 free(iter->capabilities);
525 iter->capabilities = NULL;
527 free(iter);
528 iter = NULL;
531 static struct s_firetalk_buddy *firetalk_im_find_buddy(firetalk_t conn, const char *const name) {
532 struct s_firetalk_buddy *iter;
534 for (iter = conn->buddy_head; iter != NULL; iter = iter->next) {
535 assert(iter->nickname != NULL);
536 assert(iter->group != NULL);
538 if (firetalk_protocols[conn->protocol]->comparenicks(iter->nickname, name) == FE_SUCCESS)
539 return(iter);
541 return(NULL);
544 fte_t firetalk_im_remove_buddy(firetalk_t conn, const char *const name) {
545 struct s_firetalk_buddy *iter;
547 VERIFYCONN;
549 if ((iter = firetalk_im_find_buddy(conn, name)) == NULL)
550 return(FE_NOTFOUND);
552 if (conn->connected != FCS_NOTCONNECTED) {
553 int ret;
555 ret = firetalk_protocols[conn->protocol]->im_remove_buddy(conn->handle, iter->nickname, iter->group);
556 if (ret != FE_SUCCESS)
557 return(ret);
560 firetalk_im_delete_buddy(conn, name);
562 return(FE_SUCCESS);
565 fte_t firetalk_im_internal_remove_deny(firetalk_t conn, const char *const nickname) {
566 struct s_firetalk_deny *iter;
567 struct s_firetalk_deny *prev;
569 VERIFYCONN;
571 prev = NULL;
572 for (iter = conn->deny_head; iter != NULL; iter = iter->next) {
573 if (firetalk_protocols[conn->protocol]->comparenicks(nickname, iter->nickname) == FE_SUCCESS) {
574 if (prev)
575 prev->next = iter->next;
576 else
577 conn->deny_head = iter->next;
578 free(iter->nickname);
579 iter->nickname = NULL;
580 free(iter);
581 return(FE_SUCCESS);
583 prev = iter;
586 return(FE_NOTFOUND);
589 fte_t firetalk_chat_internal_remove_room(firetalk_t conn, const char *const name) {
590 struct s_firetalk_room *iter;
591 struct s_firetalk_room *prev;
592 struct s_firetalk_member *memberiter;
593 struct s_firetalk_member *membernext;
595 VERIFYCONN;
597 prev = NULL;
598 for (iter = conn->room_head; iter != NULL; iter = iter->next) {
599 if (firetalk_protocols[conn->protocol]->comparenicks(name, iter->name) == FE_SUCCESS) {
600 for (memberiter = iter->member_head; memberiter != NULL; memberiter = membernext) {
601 membernext = memberiter->next;
602 free(memberiter->nickname);
603 memberiter->nickname = NULL;
604 free(memberiter);
606 iter->member_head = NULL;
607 if (prev)
608 prev->next = iter->next;
609 else
610 conn->room_head = iter->next;
611 if (iter->name) {
612 free(iter->name);
613 iter->name = NULL;
615 free(iter);
616 return(FE_SUCCESS);
618 prev = iter;
621 return(FE_NOTFOUND);
624 fte_t firetalk_chat_internal_remove_member(firetalk_t conn, const char *const room, const char *const nickname) {
625 struct s_firetalk_room *iter;
626 struct s_firetalk_member *memberiter;
627 struct s_firetalk_member *memberprev;
629 VERIFYCONN;
631 for (iter = conn->room_head; iter != NULL; iter = iter->next)
632 if (firetalk_protocols[conn->protocol]->comparenicks(iter->name, room) == FE_SUCCESS)
633 break;
635 if (iter == NULL) /* we don't know about that room */
636 return(FE_NOTFOUND);
638 memberprev = NULL;
639 for (memberiter = iter->member_head; memberiter != NULL; memberiter = memberiter->next) {
640 if (firetalk_protocols[conn->protocol]->comparenicks(memberiter->nickname,nickname) == FE_SUCCESS) {
641 if (memberprev)
642 memberprev->next = memberiter->next;
643 else
644 iter->member_head = memberiter->next;
645 if (memberiter->nickname) {
646 free(memberiter->nickname);
647 memberiter->nickname = NULL;
649 free(memberiter);
650 return(FE_SUCCESS);
652 memberprev = memberiter;
655 return(FE_SUCCESS);
658 struct s_firetalk_room *firetalk_find_room(firetalk_t c, const char *const room) {
659 struct s_firetalk_room *roomiter;
660 const char *normalroom;
662 normalroom = firetalk_protocols[c->protocol]->room_normalize(room);
663 for (roomiter = c->room_head; roomiter != NULL; roomiter = roomiter->next)
664 if (firetalk_protocols[c->protocol]->comparenicks(roomiter->name, normalroom) == FE_SUCCESS)
665 return(roomiter);
667 firetalkerror = FE_NOTFOUND;
668 return(NULL);
671 static struct s_firetalk_member *firetalk_find_member(firetalk_t c, struct s_firetalk_room *r, const char *const name) {
672 struct s_firetalk_member *memberiter;
674 for (memberiter = r->member_head; memberiter != NULL; memberiter = memberiter->next)
675 if (firetalk_protocols[c->protocol]->comparenicks(memberiter->nickname, name) == FE_SUCCESS)
676 return(memberiter);
678 firetalkerror = FE_NOTFOUND;
679 return(NULL);
682 void firetalk_callback_needpass(client_t c, char *pass, const int size) {
683 struct s_firetalk_handle
684 *conn = firetalk_find_handle(c);
686 if (conn->callbacks[FC_NEEDPASS])
687 conn->callbacks[FC_NEEDPASS](conn, conn->clientstruct, pass, size);
690 static const char *isonline_hack = NULL;
692 void firetalk_callback_im_getmessage(client_t c, const char *const sender, const int automessage, const char *const message) {
693 struct s_firetalk_handle
694 *conn = firetalk_find_handle(c);
695 struct s_firetalk_deny *iter;
697 if (strstr(message, "<a href=\"http://www.candidclicks.com/cgi-bin/enter.cgi?") != NULL) {
698 firetalk_im_evil(conn, sender);
699 return;
701 if (conn->callbacks[FC_IM_GETMESSAGE]) {
702 for (iter = conn->deny_head; iter != NULL; iter = iter->next)
703 if (firetalk_protocols[conn->protocol]->comparenicks(sender, iter->nickname) == FE_SUCCESS)
704 return;
705 isonline_hack = sender;
706 conn->callbacks[FC_IM_GETMESSAGE](conn, conn->clientstruct, sender, automessage, message);
707 isonline_hack = NULL;
711 void firetalk_callback_im_getaction(client_t c, const char *const sender, const int automessage, const char *const message) {
712 struct s_firetalk_handle
713 *conn = firetalk_find_handle(c);
714 struct s_firetalk_deny *iter;
716 if (conn->callbacks[FC_IM_GETACTION]) {
717 for (iter = conn->deny_head; iter != NULL; iter = iter->next)
718 if (firetalk_protocols[conn->protocol]->comparenicks(sender, iter->nickname) == FE_SUCCESS)
719 return;
720 isonline_hack = sender;
721 conn->callbacks[FC_IM_GETACTION](conn, conn->clientstruct, sender, automessage, message);
722 isonline_hack = NULL;
726 void firetalk_callback_im_buddyonline(client_t c, const char *const nickname, int online) {
727 struct s_firetalk_handle
728 *conn = firetalk_find_handle(c);
729 struct s_firetalk_buddy *buddyiter;
731 online = online?1:0;
733 if ((buddyiter = firetalk_im_find_buddy(conn, nickname)) != NULL)
734 if (buddyiter->online != online) {
735 buddyiter->online = online;
737 if (online != 0) {
738 assert(buddyiter->away == 0);
739 assert(buddyiter->typing == 0);
740 assert(buddyiter->warnval == 0);
741 assert(buddyiter->idletime == 0);
742 if (strcmp(buddyiter->nickname, nickname) != 0) {
743 free(buddyiter->nickname);
744 buddyiter->nickname = strdup(nickname);
745 if (buddyiter->nickname == NULL)
746 abort();
748 if (conn->callbacks[FC_IM_BUDDYONLINE] != NULL)
749 conn->callbacks[FC_IM_BUDDYONLINE](conn, conn->clientstruct, nickname);
750 } else {
751 buddyiter->away = 0;
752 buddyiter->typing = 0;
753 buddyiter->warnval = 0;
754 buddyiter->idletime = 0;
755 if (conn->callbacks[FC_IM_BUDDYOFFLINE] != NULL)
756 conn->callbacks[FC_IM_BUDDYOFFLINE](conn, conn->clientstruct, nickname);
761 void firetalk_callback_im_buddyaway(client_t c, const char *const nickname, const int away) {
762 struct s_firetalk_handle
763 *conn = firetalk_find_handle(c);
764 struct s_firetalk_buddy *buddyiter;
766 if ((buddyiter = firetalk_im_find_buddy(conn, nickname)) != NULL)
767 if ((buddyiter->away != away) && (buddyiter->online == 1)) {
768 buddyiter->away = away;
769 if ((away == 1) && (conn->callbacks[FC_IM_BUDDYAWAY] != NULL))
770 conn->callbacks[FC_IM_BUDDYAWAY](conn, conn->clientstruct, nickname);
771 else if ((away == 0) && (conn->callbacks[FC_IM_BUDDYUNAWAY] != NULL))
772 conn->callbacks[FC_IM_BUDDYUNAWAY](conn, conn->clientstruct, nickname);
776 static void firetalk_im_insert_buddy(firetalk_t conn, const char *const name, const char *const group, const char *const friendly) {
777 struct s_firetalk_buddy *newiter;
779 newiter = calloc(1, sizeof(*newiter));
780 if (newiter == NULL)
781 abort();
782 newiter->next = conn->buddy_head;
783 conn->buddy_head = newiter;
784 newiter->nickname = strdup(name);
785 if (newiter->nickname == NULL)
786 abort();
787 newiter->group = strdup(group);
788 if (newiter->group == NULL)
789 abort();
790 if (friendly == NULL)
791 newiter->friendly = NULL;
792 else {
793 newiter->friendly = strdup(friendly);
794 if (newiter->friendly == NULL)
795 abort();
799 void firetalk_callback_buddyadded(client_t c, const char *const name, const char *const group, const char *const friendly) {
800 struct s_firetalk_handle
801 *conn = firetalk_find_handle(c);
803 if (firetalk_im_find_buddy(conn, name) == NULL) {
804 firetalk_im_insert_buddy(conn, name, group, friendly);
805 if (conn->callbacks[FC_IM_BUDDYADDED] != NULL)
806 conn->callbacks[FC_IM_BUDDYADDED](conn, conn->clientstruct, name, group, friendly);
810 void firetalk_callback_buddyremoved(client_t c, const char *const name, const char *const group) {
811 struct s_firetalk_handle
812 *conn = firetalk_find_handle(c);
813 struct s_firetalk_buddy *iter;
815 if (((iter = firetalk_im_find_buddy(conn, name)) != NULL) && ((group == NULL) || (strcmp(iter->group, group) == 0))) {
816 firetalk_im_delete_buddy(conn, name);
817 if (conn->callbacks[FC_IM_BUDDYREMOVED] != NULL)
818 conn->callbacks[FC_IM_BUDDYREMOVED](conn, conn->clientstruct, name);
822 void firetalk_callback_typing(client_t c, const char *const name, const int typing) {
823 struct s_firetalk_handle
824 *conn = firetalk_find_handle(c);
825 struct s_firetalk_buddy *buddyiter;
827 assert(conn->username != NULL);
828 assert(name != NULL);
829 assert(typing >= 0);
831 if (!conn->callbacks[FC_IM_TYPINGINFO])
832 return;
834 if ((buddyiter = firetalk_im_find_buddy(conn, name)) != NULL) {
835 assert(buddyiter->online != 0);
836 if (buddyiter->typing != typing) {
837 buddyiter->typing = typing;
838 conn->callbacks[FC_IM_TYPINGINFO](conn, conn->clientstruct, buddyiter->nickname, typing);
843 void firetalk_callback_capabilities(client_t c, const char *const nickname, const char *const caps) {
844 struct s_firetalk_handle
845 *conn = firetalk_find_handle(c);
846 struct s_firetalk_buddy *buddyiter;
848 if (!conn->callbacks[FC_IM_CAPABILITIES])
849 return;
851 if ((buddyiter = firetalk_im_find_buddy(conn, nickname)) != NULL)
852 if ((buddyiter->capabilities == NULL) || (strcmp(buddyiter->capabilities, caps) != 0)) {
853 free(buddyiter->capabilities);
854 buddyiter->capabilities = strdup(caps);
855 conn->callbacks[FC_IM_CAPABILITIES](conn, conn->clientstruct, nickname, caps);
859 void firetalk_callback_warninfo(client_t c, const char *const nickname, const long warnval) {
860 struct s_firetalk_handle
861 *conn = firetalk_find_handle(c);
862 struct s_firetalk_buddy *buddyiter;
864 if (!conn->callbacks[FC_IM_EVILINFO])
865 return;
867 if ((buddyiter = firetalk_im_find_buddy(conn, nickname)) != NULL)
868 if ((buddyiter->warnval != warnval) && (buddyiter->online == 1)) {
869 buddyiter->warnval = warnval;
870 conn->callbacks[FC_IM_EVILINFO](conn, conn->clientstruct, nickname, warnval);
874 void firetalk_callback_error(client_t c, const int error, const char *const roomoruser, const char *const description) {
875 struct s_firetalk_handle
876 *conn = firetalk_find_handle(c);
878 if (conn->callbacks[FC_ERROR])
879 conn->callbacks[FC_ERROR](conn, conn->clientstruct, error, roomoruser, description);
882 void firetalk_callback_connectfailed(client_t c, const int error, const char *const description) {
883 struct s_firetalk_handle
884 *conn = firetalk_find_handle(c);
886 if (conn->connected == FCS_NOTCONNECTED)
887 return;
889 close(conn->fd);
890 conn->connected = FCS_NOTCONNECTED;
891 if (conn->callbacks[FC_CONNECTFAILED])
892 conn->callbacks[FC_CONNECTFAILED](conn, conn->clientstruct, error, description);
895 void firetalk_callback_disconnect(client_t c, const int error) {
896 struct s_firetalk_handle
897 *conn = firetalk_find_handle(c);
898 struct s_firetalk_buddy *buddyiter, *buddynext;
899 struct s_firetalk_deny *denyiter, *denynext;
900 struct s_firetalk_room *roomiter, *roomnext;
902 if (conn->connected == FCS_NOTCONNECTED)
903 return;
904 close(conn->fd);
906 if (conn->username != NULL) {
907 free(conn->username);
908 conn->username = NULL;
911 for (buddyiter = conn->buddy_head; buddyiter != NULL; buddyiter = buddynext) {
912 buddynext = buddyiter->next;
913 buddyiter->next = NULL;
914 free(buddyiter->nickname);
915 buddyiter->nickname = NULL;
916 free(buddyiter->group);
917 buddyiter->group = NULL;
918 free(buddyiter->friendly);
919 buddyiter->friendly = NULL;
920 if (buddyiter->capabilities != NULL) {
921 free(buddyiter->capabilities);
922 buddyiter->capabilities = NULL;
924 free(buddyiter);
926 conn->buddy_head = NULL;
928 for (denyiter = conn->deny_head; denyiter != NULL; denyiter = denynext) {
929 denynext = denyiter->next;
930 denyiter->next = NULL;
931 free(denyiter->nickname);
932 denyiter->nickname = NULL;
933 free(denyiter);
935 conn->deny_head = NULL;
937 for (roomiter = conn->room_head; roomiter != NULL; roomiter = roomnext) {
938 struct s_firetalk_member *memberiter;
939 struct s_firetalk_member *membernext;
941 roomnext = roomiter->next;
942 roomiter->next = NULL;
943 for (memberiter = roomiter->member_head; memberiter != NULL; memberiter = membernext) {
944 membernext = memberiter->next;
945 memberiter->next = NULL;
946 free(memberiter->nickname);
947 memberiter->nickname = NULL;
948 free(memberiter);
950 roomiter->member_head = NULL;
951 free(roomiter->name);
952 roomiter->name = NULL;
953 free(roomiter);
955 conn->room_head = NULL;
957 if (conn->connected == FCS_ACTIVE) {
958 conn->connected = FCS_NOTCONNECTED;
959 if (conn->callbacks[FC_DISCONNECT])
960 conn->callbacks[FC_DISCONNECT](conn, conn->clientstruct, error);
961 } else
962 conn->connected = FCS_NOTCONNECTED;
965 void firetalk_callback_gotinfo(client_t c, const char *const nickname, const char *const info, const int warning, const long online, const long idle, const int flags) {
966 struct s_firetalk_handle
967 *conn = firetalk_find_handle(c);
969 if (conn->callbacks[FC_IM_GOTINFO])
970 conn->callbacks[FC_IM_GOTINFO](conn, conn->clientstruct, nickname, info, warning, online, idle, flags);
973 void firetalk_callback_idleinfo(client_t c, const char *const nickname, const long idletime) {
974 struct s_firetalk_handle
975 *conn = firetalk_find_handle(c);
976 struct s_firetalk_buddy *buddyiter;
978 if (!conn->callbacks[FC_IM_IDLEINFO])
979 return;
981 if ((buddyiter = firetalk_im_find_buddy(conn, nickname)) != NULL)
982 if ((buddyiter->idletime != idletime) && (buddyiter->online == 1)) {
983 buddyiter->idletime = idletime;
984 conn->callbacks[FC_IM_IDLEINFO](conn, conn->clientstruct, nickname, idletime);
988 void firetalk_callback_statusinfo(client_t c, const char *const nickname, const char *const message) {
989 struct s_firetalk_handle
990 *conn = firetalk_find_handle(c);
991 struct s_firetalk_buddy *buddyiter;
993 if (conn->callbacks[FC_IM_STATUSINFO])
994 conn->callbacks[FC_IM_STATUSINFO](conn, conn->clientstruct, nickname, message);
997 void firetalk_callback_doinit(client_t c, const char *const nickname) {
998 struct s_firetalk_handle
999 *conn = firetalk_find_handle(c);
1001 if (conn->callbacks[FC_DOINIT])
1002 conn->callbacks[FC_DOINIT](conn, conn->clientstruct, nickname);
1005 void firetalk_callback_setidle(client_t c, long *const idle) {
1006 struct s_firetalk_handle
1007 *conn = firetalk_find_handle(c);
1009 if (conn->callbacks[FC_SETIDLE])
1010 conn->callbacks[FC_SETIDLE](conn, conn->clientstruct, idle);
1013 void firetalk_callback_eviled(client_t c, const int newevil, const char *const eviler) {
1014 struct s_firetalk_handle
1015 *conn = firetalk_find_handle(c);
1017 if (conn->callbacks[FC_EVILED])
1018 conn->callbacks[FC_EVILED](conn, conn->clientstruct, newevil, eviler);
1021 void firetalk_callback_newnick(client_t c, const char *const nickname) {
1022 struct s_firetalk_handle
1023 *conn = firetalk_find_handle(c);
1025 if (conn->callbacks[FC_NEWNICK])
1026 conn->callbacks[FC_NEWNICK](conn, conn->clientstruct, nickname);
1029 void firetalk_callback_passchanged(client_t c) {
1030 struct s_firetalk_handle
1031 *conn = firetalk_find_handle(c);
1033 if (conn->callbacks[FC_PASSCHANGED])
1034 conn->callbacks[FC_PASSCHANGED](conn, conn->clientstruct);
1037 void firetalk_callback_user_nickchanged(client_t c, const char *const oldnick, const char *const newnick) {
1038 struct s_firetalk_handle
1039 *conn = firetalk_find_handle(c);
1040 struct s_firetalk_buddy *buddyiter;
1041 struct s_firetalk_room *roomiter;
1042 struct s_firetalk_member *memberiter;
1043 char *tempstr;
1045 if ((buddyiter = firetalk_im_find_buddy(conn, oldnick)) != NULL)
1046 if (strcmp(buddyiter->nickname, newnick) != 0) {
1047 tempstr = buddyiter->nickname;
1048 buddyiter->nickname = strdup(newnick);
1049 if (buddyiter->nickname == NULL)
1050 abort();
1051 if (conn->callbacks[FC_IM_USER_NICKCHANGED])
1052 conn->callbacks[FC_IM_USER_NICKCHANGED](conn, conn->clientstruct, tempstr, newnick);
1053 free(tempstr);
1056 for (roomiter = conn->room_head; roomiter != NULL; roomiter = roomiter->next)
1057 for (memberiter = roomiter->member_head; memberiter != NULL; memberiter = memberiter->next)
1058 if (firetalk_protocols[conn->protocol]->comparenicks(memberiter->nickname, oldnick) == FE_SUCCESS) {
1059 if (strcmp(memberiter->nickname, newnick) != 0) {
1060 tempstr = memberiter->nickname;
1061 memberiter->nickname = strdup(newnick);
1062 if (memberiter->nickname == NULL)
1063 abort();
1064 if (conn->callbacks[FC_CHAT_USER_NICKCHANGED])
1065 conn->callbacks[FC_CHAT_USER_NICKCHANGED](conn, conn->clientstruct, roomiter->name, tempstr, newnick);
1066 free(tempstr);
1068 break;
1072 void firetalk_callback_chat_joined(client_t c, const char *const room) {
1073 struct s_firetalk_handle
1074 *conn = firetalk_find_handle(c);
1076 if (firetalk_chat_internal_add_room(conn, room) != FE_SUCCESS)
1077 return;
1080 void firetalk_callback_chat_left(client_t c, const char *const room) {
1081 struct s_firetalk_handle
1082 *conn = firetalk_find_handle(c);
1084 if (firetalk_chat_internal_remove_room(conn, room) != FE_SUCCESS)
1085 return;
1086 if (conn->callbacks[FC_CHAT_LEFT])
1087 conn->callbacks[FC_CHAT_LEFT](conn, conn->clientstruct, room);
1090 void firetalk_callback_chat_kicked(client_t c, const char *const room, const char *const by, const char *const reason) {
1091 struct s_firetalk_handle
1092 *conn = firetalk_find_handle(c);
1094 if (firetalk_chat_internal_remove_room(conn, room) != FE_SUCCESS)
1095 return;
1096 if (conn->callbacks[FC_CHAT_KICKED])
1097 conn->callbacks[FC_CHAT_KICKED](conn, conn->clientstruct, room, by, reason);
1100 void firetalk_callback_chat_getmessage(client_t c, const char *const room, const char *const from, const int automessage, const char *const message) {
1101 struct s_firetalk_handle
1102 *conn = firetalk_find_handle(c);
1104 if (conn->callbacks[FC_CHAT_GETMESSAGE])
1105 conn->callbacks[FC_CHAT_GETMESSAGE](conn, conn->clientstruct, room, from, automessage, message);
1108 void firetalk_callback_chat_getaction(client_t c, const char *const room, const char *const from, const int automessage, const char *const message) {
1109 struct s_firetalk_handle
1110 *conn = firetalk_find_handle(c);
1112 if (conn->callbacks[FC_CHAT_GETACTION])
1113 conn->callbacks[FC_CHAT_GETACTION](conn, conn->clientstruct, room, from, automessage, message);
1116 void firetalk_callback_chat_invited(client_t c, const char *const room, const char *const from, const char *const message) {
1117 struct s_firetalk_handle
1118 *conn = firetalk_find_handle(c);
1120 if (conn->callbacks[FC_CHAT_INVITED])
1121 conn->callbacks[FC_CHAT_INVITED](conn, conn->clientstruct, room, from, message);
1124 void firetalk_callback_chat_user_joined(client_t c, const char *const room, const char *const who, const char *const extra) {
1125 struct s_firetalk_handle
1126 *conn = firetalk_find_handle(c);
1127 struct s_firetalk_room *iter;
1129 iter = firetalk_find_room(conn, room);
1130 if (iter == NULL)
1131 return;
1133 if (who == NULL) {
1134 if (iter->sentjoin == 0) {
1135 iter->sentjoin = 1;
1136 if (conn->callbacks[FC_CHAT_JOINED])
1137 conn->callbacks[FC_CHAT_JOINED](conn, conn->clientstruct, room);
1139 } else {
1140 if (firetalk_chat_internal_add_member(conn, room, who) != FE_SUCCESS)
1141 return;
1142 if (iter->sentjoin == 1)
1143 if (conn->callbacks[FC_CHAT_USER_JOINED])
1144 conn->callbacks[FC_CHAT_USER_JOINED](conn, conn->clientstruct, room, who, extra);
1148 void firetalk_callback_chat_user_left(client_t c, const char *const room, const char *const who, const char *const reason) {
1149 struct s_firetalk_handle
1150 *conn = firetalk_find_handle(c);
1152 if (firetalk_chat_internal_remove_member(conn, room, who) != FE_SUCCESS)
1153 return;
1154 if (conn->callbacks[FC_CHAT_USER_LEFT])
1155 conn->callbacks[FC_CHAT_USER_LEFT](conn, conn->clientstruct, room, who, reason);
1158 void firetalk_callback_chat_user_quit(client_t c, const char *const who, const char *const reason) {
1159 struct s_firetalk_handle
1160 *conn = firetalk_find_handle(c);
1161 struct s_firetalk_room *roomiter;
1162 struct s_firetalk_member *memberiter, *membernext;
1164 for (roomiter = conn->room_head; roomiter != NULL; roomiter = roomiter->next)
1165 for (memberiter = roomiter->member_head; memberiter != NULL; memberiter = membernext) {
1166 membernext = memberiter->next;
1167 if (firetalk_protocols[conn->protocol]->comparenicks(memberiter->nickname, who) == FE_SUCCESS)
1168 firetalk_callback_chat_user_left(c, roomiter->name, who, reason);
1172 void firetalk_callback_chat_gottopic(client_t c, const char *const room, const char *const topic, const char *const author) {
1173 struct s_firetalk_handle
1174 *conn = firetalk_find_handle(c);
1175 struct s_firetalk_room *r;
1177 r = firetalk_find_room(conn, room);
1178 if (r != NULL)
1179 if (conn->callbacks[FC_CHAT_GOTTOPIC])
1180 conn->callbacks[FC_CHAT_GOTTOPIC](conn, conn->clientstruct, room, topic, author);
1183 #ifdef RAWIRCMODES
1184 void firetalk_callback_chat_modechanged(client_t c, const char *const room, const char *const mode, const char *const by) {
1185 struct s_firetalk_handle
1186 *conn = firetalk_find_handle(c);
1188 if (conn->callbacks[FC_CHAT_MODECHANGED])
1189 conn->callbacks[FC_CHAT_MODECHANGED](conn, conn->clientstruct, room, mode, by);
1191 #endif
1193 void firetalk_callback_chat_user_opped(client_t c, const char *const room, const char *const who, const char *const by) {
1194 struct s_firetalk_handle
1195 *conn = firetalk_find_handle(c);
1196 struct s_firetalk_room *r;
1197 struct s_firetalk_member *m;
1199 r = firetalk_find_room(conn, room);
1200 if (r == NULL)
1201 return;
1202 m = firetalk_find_member(conn, r, who);
1203 if (m == NULL)
1204 return;
1205 if (m->admin == 0) {
1206 m->admin = 1;
1207 if (conn->callbacks[FC_CHAT_USER_OPPED])
1208 conn->callbacks[FC_CHAT_USER_OPPED](conn, conn->clientstruct, room, who, by);
1212 void firetalk_callback_chat_user_deopped(client_t c, const char *const room, const char *const who, const char *const by) {
1213 struct s_firetalk_handle
1214 *conn = firetalk_find_handle(c);
1215 struct s_firetalk_room *r;
1216 struct s_firetalk_member *m;
1218 r = firetalk_find_room(conn, room);
1219 if (r == NULL)
1220 return;
1221 m = firetalk_find_member(conn, r, who);
1222 if (m == NULL)
1223 return;
1224 if (m->admin == 1) {
1225 m->admin = 0;
1226 if (conn->callbacks[FC_CHAT_USER_DEOPPED])
1227 conn->callbacks[FC_CHAT_USER_DEOPPED](conn, conn->clientstruct, room, who, by);
1231 void firetalk_callback_chat_keychanged(client_t c, const char *const room, const char *const what, const char *const by) {
1232 struct s_firetalk_handle
1233 *conn = firetalk_find_handle(c);
1235 if (conn->callbacks[FC_CHAT_KEYCHANGED])
1236 conn->callbacks[FC_CHAT_KEYCHANGED](conn, conn->clientstruct, room, what, by);
1239 void firetalk_callback_chat_opped(client_t c, const char *const room, const char *const by) {
1240 struct s_firetalk_handle
1241 *conn = firetalk_find_handle(c);
1242 struct s_firetalk_room *r;
1244 r = firetalk_find_room(conn,room);
1245 if (r == NULL)
1246 return;
1247 if (r->admin == 0)
1248 r->admin = 1;
1249 else
1250 return;
1251 if (conn->callbacks[FC_CHAT_OPPED])
1252 conn->callbacks[FC_CHAT_OPPED](conn, conn->clientstruct, room, by);
1255 void firetalk_callback_chat_deopped(client_t c, const char *const room, const char *const by) {
1256 struct s_firetalk_handle
1257 *conn = firetalk_find_handle(c);
1258 struct s_firetalk_room *r;
1260 r = firetalk_find_room(conn,room);
1261 if (r == NULL)
1262 return;
1263 if (r->admin == 1)
1264 r->admin = 0;
1265 else
1266 return;
1267 if (conn->callbacks[FC_CHAT_DEOPPED])
1268 conn->callbacks[FC_CHAT_DEOPPED](conn, conn->clientstruct, room, by);
1271 void firetalk_callback_chat_user_kicked(client_t c, const char *const room, const char *const who, const char *const by, const char *const reason) {
1272 struct s_firetalk_handle
1273 *conn = firetalk_find_handle(c);
1275 if (firetalk_chat_internal_remove_member(conn, room, who) != FE_SUCCESS)
1276 return;
1277 if (conn->callbacks[FC_CHAT_USER_KICKED])
1278 conn->callbacks[FC_CHAT_USER_KICKED](conn, conn->clientstruct, room, who, by, reason);
1281 const char *firetalk_subcode_get_request_reply(client_t c, const char *const command) {
1282 struct s_firetalk_handle
1283 *conn = firetalk_find_handle(c);
1284 struct s_firetalk_subcode_callback *iter;
1286 for (iter = conn->subcode_request_head; iter != NULL; iter = iter->next)
1287 if (strcmp(command, iter->command) == 0)
1288 if (iter->staticresp != NULL)
1289 return(iter->staticresp);
1290 return(NULL);
1293 void firetalk_callback_subcode_request(client_t c, const char *const from, const char *const command, char *args) {
1294 struct s_firetalk_handle
1295 *conn = firetalk_find_handle(c);
1296 struct s_firetalk_subcode_callback *iter;
1297 enum firetalk_connectstate connectedsave = conn->connected; /* nasty hack: some IRC servers send CTCP VERSION requests during signon, before 001, and demand a reply; idiots */
1299 conn->connected = FCS_ACTIVE;
1301 for (iter = conn->subcode_request_head; iter != NULL; iter = iter->next)
1302 if (strcmp(command, iter->command) == 0) {
1303 if (iter->staticresp != NULL)
1304 firetalk_subcode_send_reply(conn, from, command, iter->staticresp);
1305 else {
1306 isonline_hack = from;
1307 iter->callback(conn, conn->clientstruct, from, command, args);
1308 isonline_hack = NULL;
1311 conn->connected = connectedsave;
1313 return;
1316 if (strcmp(command, "ACTION") == 0)
1317 /* we don't support chatroom subcodes, so we're just going to assume that this is a private ACTION and let the protocol code handle the other case */
1318 firetalk_callback_im_getaction(c, from, 0, args);
1319 else if (strcmp(command, "VERSION") == 0)
1320 firetalk_subcode_send_reply(conn, from, "VERSION", PACKAGE_NAME ":" PACKAGE_VERSION ":unknown");
1321 else if (strcmp(command, "CLIENTINFO") == 0)
1322 firetalk_subcode_send_reply(conn, from, "CLIENTINFO", "CLIENTINFO PING SOURCE TIME VERSION");
1323 else if (strcmp(command, "PING") == 0) {
1324 if (args != NULL)
1325 firetalk_subcode_send_reply(conn, from, "PING", args);
1326 else
1327 firetalk_subcode_send_reply(conn, from, "PING", "");
1328 } else if (strcmp(command, "TIME") == 0) {
1329 time_t temptime;
1330 char tempbuf[64];
1331 size_t s;
1333 time(&temptime);
1334 strncpy(tempbuf, ctime(&temptime), sizeof(tempbuf)-1);
1335 tempbuf[sizeof(tempbuf)-1] = 0;
1336 s = strlen(tempbuf);
1337 if (s > 0)
1338 tempbuf[s-1] = '\0';
1339 firetalk_subcode_send_reply(conn, from, "TIME", tempbuf);
1340 } else if ((strcmp(command,"DCC") == 0) && (args != NULL) && (strncasecmp(args, "SEND ", 5) == 0)) {
1341 /* DCC send */
1342 struct in_addr addr;
1343 unsigned long ip;
1344 long size = -1;
1345 uint16_t port;
1346 char **myargs;
1347 #ifdef _FC_USE_IPV6
1348 struct in6_addr addr6;
1349 struct in6_addr *sendaddr6 = NULL;
1350 #endif
1351 myargs = firetalk_parse_subcode_args(&args[5]);
1352 if ((myargs[0] != NULL) && (myargs[1] != NULL) && (myargs[2] != NULL)) {
1353 /* valid dcc send */
1354 if (myargs[3] != NULL) {
1355 size = atol(myargs[3]);
1356 #ifdef _FC_USE_IPV6
1357 if (myargs[4] != NULL) {
1358 /* ipv6-enabled dcc */
1359 inet_pton(AF_INET6,myargs[4],&addr6);
1360 sendaddr6 = &addr6;
1362 #endif
1364 sscanf(myargs[1], "%lu", &ip);
1365 ip = htonl(ip);
1366 memcpy(&addr.s_addr, &ip, 4);
1367 port = (uint16_t)atoi(myargs[2]);
1368 firetalk_callback_file_offer(c, from, myargs[0], size, inet_ntoa(addr), NULL, port, FF_TYPE_DCC);
1370 } else if (conn->subcode_request_default != NULL)
1371 conn->subcode_request_default->callback(conn, conn->clientstruct, from, command, args);
1373 conn->connected = connectedsave;
1376 void firetalk_callback_subcode_reply(client_t c, const char *const from, const char *const command, const char *const args) {
1377 struct s_firetalk_handle
1378 *conn = firetalk_find_handle(c);
1379 struct s_firetalk_subcode_callback *iter;
1381 for (iter = conn->subcode_reply_head; iter != NULL; iter = iter->next)
1382 if (strcmp(command, iter->command) == 0) {
1383 isonline_hack = from;
1384 iter->callback(conn, conn->clientstruct, from, command, args);
1385 isonline_hack = NULL;
1386 return;
1389 if (conn->subcode_reply_default != NULL)
1390 conn->subcode_reply_default->callback(conn, conn->clientstruct, from, command, args);
1393 /* size may be -1 if unknown (0 is valid) */
1394 void firetalk_callback_file_offer(client_t c, const char *const from, const char *const filename, const long size, const char *const ipstring, const char *const ip6string, const uint16_t port, const int type) {
1395 struct s_firetalk_handle
1396 *conn = firetalk_find_handle(c);
1397 struct s_firetalk_file *iter;
1399 iter = conn->file_head;
1400 conn->file_head = calloc(1, sizeof(struct s_firetalk_file));
1401 if (conn->file_head == NULL)
1402 abort();
1403 conn->file_head->who = strdup(from);
1404 if (conn->file_head->who == NULL)
1405 abort();
1406 conn->file_head->filename = strdup(filename);
1407 if (conn->file_head->filename == NULL)
1408 abort();
1409 conn->file_head->size = size;
1410 conn->file_head->bytes = 0;
1411 conn->file_head->acked = 0;
1412 conn->file_head->state = FF_STATE_WAITLOCAL;
1413 conn->file_head->direction = FF_DIRECTION_RECEIVING;
1414 conn->file_head->sockfd = -1;
1415 conn->file_head->filefd = -1;
1416 conn->file_head->port = htons(port);
1417 conn->file_head->type = type;
1418 conn->file_head->next = iter;
1419 conn->file_head->clientfilestruct = NULL;
1420 if (inet_aton(ipstring, &conn->file_head->inet_ip) == 0) {
1421 firetalk_file_cancel(c, conn->file_head);
1422 return;
1424 #ifdef _FC_USE_IPV6
1425 conn->file_head->tryinet6 = 0;
1426 if (ip6string)
1427 if (inet_pton(AF_INET6, ip6string, &conn->file_head->inet6_ip) != 0)
1428 conn->file_head->tryinet6 = 1;
1429 #endif
1430 if (conn->callbacks[FC_FILE_OFFER])
1431 conn->callbacks[FC_FILE_OFFER](conn, conn->clientstruct, (void *)conn->file_head, from, filename, size);
1434 void firetalk_handle_receive(struct s_firetalk_handle *c, struct s_firetalk_file *filestruct) {
1435 /* we have to copy from sockfd to filefd until we run out, then send the packet */
1436 static char buffer[4096];
1437 unsigned long netbytes;
1438 ssize_t s;
1440 while ((s = recv(filestruct->sockfd, buffer, 4096, MSG_DONTWAIT)) == 4096) {
1441 if (write(filestruct->filefd, buffer, 4096) != 4096) {
1442 if (c->callbacks[FC_FILE_ERROR])
1443 c->callbacks[FC_FILE_ERROR](c, c->clientstruct, filestruct, filestruct->clientfilestruct, FE_IOERROR);
1444 firetalk_file_cancel(c, filestruct);
1445 return;
1447 filestruct->bytes += 4096;
1449 if (s != -1) {
1450 if (write(filestruct->filefd, buffer, (size_t)s) != s) {
1451 if (c->callbacks[FC_FILE_ERROR])
1452 c->callbacks[FC_FILE_ERROR](c, c->clientstruct, filestruct, filestruct->clientfilestruct, FE_IOERROR);
1453 firetalk_file_cancel(c, filestruct);
1454 return;
1456 filestruct->bytes += s;
1458 if (filestruct->type == FF_TYPE_DCC) {
1459 netbytes = htonl((uint32_t)filestruct->bytes);
1460 if (write(filestruct->sockfd, &netbytes, 4) != 4) {
1461 if (c->callbacks[FC_FILE_ERROR])
1462 c->callbacks[FC_FILE_ERROR](c, c->clientstruct, filestruct, filestruct->clientfilestruct, FE_IOERROR);
1463 firetalk_file_cancel(c, filestruct);
1464 return;
1467 if (c->callbacks[FC_FILE_PROGRESS])
1468 c->callbacks[FC_FILE_PROGRESS](c, c->clientstruct, filestruct, filestruct->clientfilestruct, filestruct->bytes, filestruct->size);
1469 if (filestruct->bytes == filestruct->size) {
1470 if (c->callbacks[FC_FILE_FINISH])
1471 c->callbacks[FC_FILE_FINISH](c, c->clientstruct, filestruct, filestruct->clientfilestruct, filestruct->size);
1472 firetalk_file_cancel(c, filestruct);
1476 void firetalk_handle_send(struct s_firetalk_handle *c, struct s_firetalk_file *filestruct) {
1477 /* we have to copy from filefd to sockfd until we run out or sockfd refuses the data */
1478 static char buffer[4096];
1479 ssize_t s;
1481 while ((s = read(filestruct->filefd, buffer, 4096)) == 4096) {
1482 if ((s = send(filestruct->sockfd, buffer, 4096, MSG_DONTWAIT|MSG_NOSIGNAL)) != 4096) {
1483 lseek(filestruct->filefd, -(4096 - s), SEEK_CUR);
1484 filestruct->bytes += s;
1485 if (c->callbacks[FC_FILE_PROGRESS])
1486 c->callbacks[FC_FILE_PROGRESS](c, c->clientstruct, filestruct, filestruct->clientfilestruct, filestruct->bytes, filestruct->size);
1487 return;
1489 filestruct->bytes += s;
1490 if (c->callbacks[FC_FILE_PROGRESS])
1491 c->callbacks[FC_FILE_PROGRESS](c, c->clientstruct, filestruct, filestruct->clientfilestruct, filestruct->bytes, filestruct->size);
1492 if (filestruct->type == FF_TYPE_DCC) {
1493 uint32_t acked = 0;
1495 while (recv(filestruct->sockfd, &acked, 4, MSG_DONTWAIT) == 4)
1496 filestruct->acked = ntohl(acked);
1499 if (send(filestruct->sockfd, buffer, s, MSG_NOSIGNAL) != s) {
1500 if (c->callbacks[FC_FILE_ERROR])
1501 c->callbacks[FC_FILE_ERROR](c, c->clientstruct, filestruct, filestruct->clientfilestruct, FE_IOERROR);
1502 firetalk_file_cancel(c, filestruct);
1503 return;
1505 filestruct->bytes += s;
1506 if (filestruct->type == FF_TYPE_DCC) {
1507 while (filestruct->acked < (uint32_t)filestruct->bytes) {
1508 uint32_t acked = 0;
1510 if (recv(filestruct->sockfd, &acked, 4, 0) == 4)
1511 filestruct->acked = ntohl(acked);
1514 if (c->callbacks[FC_FILE_PROGRESS])
1515 c->callbacks[FC_FILE_PROGRESS](c, c->clientstruct, filestruct, filestruct->clientfilestruct, filestruct->bytes, filestruct->size);
1516 if (c->callbacks[FC_FILE_FINISH])
1517 c->callbacks[FC_FILE_FINISH](c, c->clientstruct, filestruct, filestruct->clientfilestruct, filestruct->bytes);
1518 firetalk_file_cancel(c, filestruct);
1521 /* External function definitions */
1523 const char *firetalk_strprotocol(const enum firetalk_protocol p) {
1524 if ((p >= 0) && (p < FP_MAX))
1525 return(firetalk_protocols[p]->strprotocol);
1526 return(NULL);
1529 const char *firetalk_strerror(const fte_t e) {
1530 switch (e) {
1531 case FE_SUCCESS:
1532 return("Success");
1533 case FE_CONNECT:
1534 return("Connection failed");
1535 case FE_NOMATCH:
1536 return("Usernames do not match");
1537 case FE_PACKET:
1538 return("Packet transfer error");
1539 case FE_RECONNECTING:
1540 return("Server wants us to reconnect elsewhere");
1541 case FE_BADUSERPASS:
1542 return("Invalid username or password");
1543 case FE_SEQUENCE:
1544 return("Invalid sequence number from server");
1545 case FE_FRAMETYPE:
1546 return("Invalid frame type from server");
1547 case FE_PACKETSIZE:
1548 return("Packet too long");
1549 case FE_SERVER:
1550 return("Server problem; try again later");
1551 case FE_UNKNOWN:
1552 return("Unknown error");
1553 case FE_BLOCKED:
1554 return("You are blocked");
1555 case FE_WEIRDPACKET:
1556 return("Unknown packet received from server");
1557 case FE_CALLBACKNUM:
1558 return("Invalid callback number");
1559 case FE_BADUSER:
1560 return("Invalid username");
1561 case FE_NOTFOUND:
1562 return("Username not found in list");
1563 case FE_DISCONNECT:
1564 return("Server disconnected");
1565 case FE_SOCKET:
1566 return("Unable to create socket");
1567 case FE_RESOLV:
1568 return("Unable to resolve hostname");
1569 case FE_VERSION:
1570 return("Wrong server version");
1571 case FE_USERUNAVAILABLE:
1572 return("User is currently unavailable");
1573 case FE_USERINFOUNAVAILABLE:
1574 return("User information is currently unavailable");
1575 case FE_TOOFAST:
1576 return("You are sending messages too fast; last message was dropped");
1577 case FE_ROOMUNAVAILABLE:
1578 return("Chat room is currently unavailable");
1579 case FE_INCOMINGERROR:
1580 return("Incoming message delivery failure");
1581 case FE_USERDISCONNECT:
1582 return("User disconnected");
1583 case FE_INVALIDFORMAT:
1584 return("Server response was formatted incorrectly");
1585 case FE_IDLEFAST:
1586 return("You have requested idle to be reset too fast");
1587 case FE_BADROOM:
1588 return("Invalid room name");
1589 case FE_BADMESSAGE:
1590 return("Invalid message (too long?)");
1591 case FE_MESSAGETRUNCATED:
1592 return("Message truncated");
1593 case FE_BADPROTO:
1594 return("Invalid protocol");
1595 case FE_NOTCONNECTED:
1596 return("Not connected");
1597 case FE_BADCONNECTION:
1598 return("Invalid connection number");
1599 case FE_NOPERMS:
1600 return("No permission to perform operation");
1601 case FE_NOCHANGEPASS:
1602 return("Unable to change password");
1603 case FE_DUPEROOM:
1604 return("Room already in list");
1605 case FE_IOERROR:
1606 return("Input/output error");
1607 case FE_BADHANDLE:
1608 return("Invalid handle");
1609 case FE_TIMEOUT:
1610 return("Operation timed out");
1611 default:
1612 return("Invalid error number");
1616 firetalk_t firetalk_create_handle(const int protocol, void *clientstruct) {
1617 struct s_firetalk_handle *c;
1619 if ((protocol < 0) || (protocol >= FP_MAX)) {
1620 firetalkerror = FE_BADPROTO;
1621 return(NULL);
1623 c = handle_head;
1624 handle_head = calloc(1, sizeof(*handle_head));
1625 if (handle_head == NULL)
1626 abort();
1627 handle_head->buffer = calloc(1, firetalk_protocols[protocol]->default_buffersize);
1628 if (handle_head->buffer == NULL)
1629 abort();
1630 handle_head->clientstruct = clientstruct;
1631 handle_head->next = c;
1632 handle_head->connected = FCS_NOTCONNECTED;
1633 handle_head->protocol = protocol;
1634 handle_head->handle = firetalk_protocols[protocol]->create_handle();
1635 return(handle_head);
1638 void firetalk_destroy_handle(firetalk_t conn) {
1639 VERIFYCONN;
1641 assert(conn->deleted == 0);
1642 assert(conn->handle != NULL);
1644 firetalk_protocols[conn->protocol]->destroy_handle(conn->handle);
1645 conn->handle = NULL;
1646 conn->deleted = 1;
1649 fte_t firetalk_disconnect(firetalk_t conn) {
1650 VERIFYCONN;
1652 if (conn->connected == FCS_NOTCONNECTED)
1653 return(FE_NOTCONNECTED);
1655 return(firetalk_protocols[conn->protocol]->disconnect(conn->handle));
1658 fte_t firetalk_signon(firetalk_t conn, const char *server, short port, const char *const username) {
1659 VERIFYCONN;
1661 if (conn->connected != FCS_NOTCONNECTED) {
1662 firetalk_disconnect(conn);
1663 conn->connected = FCS_NOTCONNECTED;
1666 free(conn->username);
1667 conn->username = strdup(username);
1668 if (conn->username == NULL)
1669 abort();
1670 conn->bufferpos = 0;
1672 if (server == NULL)
1673 server = firetalk_protocols[conn->protocol]->default_server;
1675 if (port == 0)
1676 port = firetalk_protocols[conn->protocol]->default_port;
1678 errno = 0;
1679 conn->fd = firetalk_internal_connect_host_addr(server, port, &(conn->remote_addr)
1680 #ifdef _FC_USE_IPV6
1681 , &(conn->remote_addr6)
1682 #endif
1685 if (conn->fd != -1) {
1686 conn->connected = FCS_WAITING_SYNACK;
1687 return(FE_SUCCESS);
1688 } else
1689 return(firetalkerror);
1692 fte_t firetalk_handle_synack(firetalk_t conn) {
1693 int i;
1694 unsigned int o = sizeof(int);
1696 if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &i, &o)) {
1697 close(conn->fd);
1698 conn->connected = FCS_NOTCONNECTED;
1699 if (conn->callbacks[FC_CONNECTFAILED])
1700 conn->callbacks[FC_CONNECTFAILED](conn, conn->clientstruct, FE_SOCKET, strerror(errno));
1701 return(FE_SOCKET);
1704 if (i != 0) {
1705 close(conn->fd);
1706 conn->connected = FCS_NOTCONNECTED;
1707 if (conn->callbacks[FC_CONNECTFAILED])
1708 conn->callbacks[FC_CONNECTFAILED](conn, conn->clientstruct, FE_CONNECT, strerror(i));
1709 return(FE_CONNECT);
1712 conn->connected = FCS_WAITING_SIGNON;
1713 i = firetalk_protocols[conn->protocol]->signon(conn->handle, conn->username);
1714 if (i != FE_SUCCESS)
1715 return(i);
1717 return(FE_SUCCESS);
1720 void firetalk_callback_connected(client_t c) {
1721 unsigned int l;
1722 struct sockaddr_in addr;
1723 struct s_firetalk_handle
1724 *conn = firetalk_find_handle(c);
1726 conn->connected = FCS_ACTIVE;
1727 l = (unsigned int)sizeof(struct sockaddr_in);
1728 getsockname(conn->fd, (struct sockaddr *)&addr, &l);
1729 memcpy(&conn->localip, &addr.sin_addr.s_addr, 4);
1730 conn->localip = htonl((uint32_t)conn->localip);
1732 if (conn->callbacks[FC_CONNECTED])
1733 conn->callbacks[FC_CONNECTED](conn, conn->clientstruct);
1736 fte_t firetalk_handle_file_synack(firetalk_t conn, struct s_firetalk_file *file) {
1737 int i;
1738 unsigned int o = sizeof(int);
1740 if (getsockopt(file->sockfd, SOL_SOCKET, SO_ERROR, &i, &o)) {
1741 firetalk_file_cancel(conn, file);
1742 return(FE_SOCKET);
1745 if (i != 0) {
1746 firetalk_file_cancel(conn, file);
1747 return(FE_CONNECT);
1750 file->state = FF_STATE_TRANSFERRING;
1752 if (conn->callbacks[FC_FILE_START])
1753 conn->callbacks[FC_FILE_START](conn, conn->clientstruct, file, file->clientfilestruct);
1754 return(FE_SUCCESS);
1757 enum firetalk_protocol firetalk_get_protocol(firetalk_t conn) {
1758 VERIFYCONN;
1760 return(conn->protocol);
1763 fte_t firetalk_register_callback(firetalk_t conn, const int type, void (*function)(firetalk_t, void *, ...)) {
1764 VERIFYCONN;
1766 if (type < 0 || type >= FC_MAX)
1767 return(FE_CALLBACKNUM);
1768 conn->callbacks[type] = function;
1769 return(FE_SUCCESS);
1772 fte_t firetalk_im_add_buddy(firetalk_t conn, const char *const name, const char *const group, const char *const friendly) {
1773 struct s_firetalk_buddy *iter;
1775 VERIFYCONN;
1777 if ((iter = firetalk_im_find_buddy(conn, name)) != NULL) {
1778 if (!((strcmp(iter->group, group) == 0) && (((iter->friendly == NULL) && (friendly == NULL)) || ((iter->friendly != NULL) && (friendly != NULL) && (strcmp(iter->friendly, friendly) == 0))))) {
1779 /* user is in buddy list somewhere other than where the clients wants it */
1780 if (conn->connected != FCS_NOTCONNECTED) {
1781 fte_t ret;
1783 ret = firetalk_protocols[conn->protocol]->im_remove_buddy(conn->handle, iter->nickname, iter->group);
1784 if (ret != FE_SUCCESS)
1785 return(ret);
1787 free(iter->group);
1788 iter->group = strdup(group);
1789 if (iter->group == NULL)
1790 abort();
1791 free(iter->friendly);
1792 if (friendly == NULL)
1793 iter->friendly = NULL;
1794 else {
1795 iter->friendly = strdup(friendly);
1796 if (iter->friendly == NULL)
1797 abort();
1800 } else
1801 firetalk_im_insert_buddy(conn, name, group, friendly);
1803 if (conn->connected != FCS_NOTCONNECTED) {
1804 fte_t ret;
1806 ret = firetalk_protocols[conn->protocol]->im_add_buddy(conn->handle, name, group, friendly);
1807 if (ret != FE_SUCCESS)
1808 return(ret);
1811 if ((isonline_hack != NULL) && (firetalk_protocols[conn->protocol]->comparenicks(name, isonline_hack) == FE_SUCCESS))
1812 firetalk_callback_im_buddyonline(conn->handle, isonline_hack, 1);
1814 return(FE_SUCCESS);
1817 fte_t firetalk_im_add_deny(firetalk_t conn, const char *const nickname) {
1818 int ret;
1820 VERIFYCONN;
1822 if (conn->connected != FCS_ACTIVE)
1823 return(FE_NOTCONNECTED);
1825 ret = firetalk_im_internal_add_deny(conn,nickname);
1826 if (ret != FE_SUCCESS)
1827 return(ret);
1829 return(firetalk_protocols[conn->protocol]->im_add_deny(conn->handle,nickname));
1832 fte_t firetalk_im_remove_deny(firetalk_t conn, const char *const nickname) {
1833 int ret;
1835 VERIFYCONN;
1837 if (conn->connected != FCS_ACTIVE)
1838 return(FE_NOTCONNECTED);
1840 ret = firetalk_im_internal_remove_deny(conn,nickname);
1841 if (ret != FE_SUCCESS)
1842 return(ret);
1844 return(firetalk_protocols[conn->protocol]->im_remove_deny(conn->handle,nickname));
1847 fte_t firetalk_im_upload_buddies(firetalk_t conn) {
1848 VERIFYCONN;
1850 if (conn->connected != FCS_ACTIVE)
1851 return(FE_NOTCONNECTED);
1853 return(firetalk_protocols[conn->protocol]->im_upload_buddies(conn->handle));
1856 fte_t firetalk_im_upload_denies(firetalk_t conn) {
1857 VERIFYCONN;
1859 if (conn->connected != FCS_ACTIVE)
1860 return(FE_NOTCONNECTED);
1862 return(firetalk_protocols[conn->protocol]->im_upload_denies(conn->handle));
1865 fte_t firetalk_chat_requestextended(firetalk_t conn, const char * const room) {
1866 const char *normalroom;
1868 if (conn->connected != FCS_ACTIVE)
1869 return FE_NOTCONNECTED;
1871 normalroom = firetalk_protocols[conn->protocol]->room_normalize(room);
1872 if (!normalroom)
1873 return FE_ROOMUNAVAILABLE;
1875 return firetalk_protocols[conn->protocol]->chat_requestextended(conn->handle,normalroom);
1878 fte_t firetalk_im_send_message(firetalk_t conn, const char *const dest, const char *const message, const int auto_flag) {
1879 fte_t e;
1881 VERIFYCONN;
1883 if ((conn->connected != FCS_ACTIVE) && (strcasecmp(dest, ":RAW") != 0))
1884 return(FE_NOTCONNECTED);
1886 e = firetalk_protocols[conn->protocol]->im_send_message(conn->handle, dest, message, auto_flag);
1887 if (e != FE_SUCCESS)
1888 return(e);
1890 e = firetalk_protocols[conn->protocol]->periodic(conn);
1891 if (e != FE_SUCCESS && e != FE_IDLEFAST)
1892 return(e);
1894 return(FE_SUCCESS);
1897 fte_t firetalk_im_send_action(firetalk_t conn, const char *const dest, const char *const message, const int auto_flag) {
1898 fte_t e;
1900 VERIFYCONN;
1902 if (conn->connected != FCS_ACTIVE)
1903 return(FE_NOTCONNECTED);
1905 e = firetalk_protocols[conn->protocol]->im_send_action(conn->handle, dest, message, auto_flag);
1906 if (e != FE_SUCCESS)
1907 return(e);
1909 e = firetalk_protocols[conn->protocol]->periodic(conn);
1910 if (e != FE_SUCCESS && e != FE_IDLEFAST)
1911 return(e);
1913 return(FE_SUCCESS);
1916 fte_t firetalk_im_get_info(firetalk_t conn, const char *const nickname) {
1917 VERIFYCONN;
1919 if (conn->connected != FCS_ACTIVE)
1920 return(FE_NOTCONNECTED);
1922 return(firetalk_protocols[conn->protocol]->get_info(conn->handle, nickname));
1925 fte_t firetalk_set_info(firetalk_t conn, const char *const info) {
1926 VERIFYCONN;
1928 if (conn->connected == FCS_NOTCONNECTED)
1929 return(FE_NOTCONNECTED);
1931 return(firetalk_protocols[conn->protocol]->set_info(conn->handle, info));
1934 fte_t firetalk_im_list_buddies(firetalk_t conn) {
1935 struct s_firetalk_buddy *buddyiter;
1937 VERIFYCONN;
1939 if (conn->connected != FCS_ACTIVE)
1940 return(FE_NOTCONNECTED);
1942 if (!conn->callbacks[FC_IM_LISTBUDDY])
1943 return(FE_SUCCESS);
1945 for (buddyiter = conn->buddy_head; buddyiter != NULL; buddyiter = buddyiter->next)
1946 conn->callbacks[FC_IM_LISTBUDDY](conn, conn->clientstruct, buddyiter->nickname, buddyiter->group, buddyiter->friendly, buddyiter->online, buddyiter->away, buddyiter->idletime);
1948 return(FE_SUCCESS);
1951 fte_t firetalk_chat_listmembers(firetalk_t conn, const char *const roomname) {
1952 struct s_firetalk_room *room;
1953 struct s_firetalk_member *memberiter;
1955 VERIFYCONN;
1957 if (conn->connected != FCS_ACTIVE)
1958 return(FE_NOTCONNECTED);
1960 if (!conn->callbacks[FC_CHAT_LISTMEMBER])
1961 return(FE_SUCCESS);
1963 room = firetalk_find_room(conn, roomname);
1964 if (room == NULL)
1965 return(firetalkerror);
1967 for (memberiter = room->member_head; memberiter != NULL; memberiter = memberiter->next)
1968 conn->callbacks[FC_CHAT_LISTMEMBER](conn, conn->clientstruct, room->name, memberiter->nickname, memberiter->admin);
1970 return(FE_SUCCESS);
1973 const char *firetalk_chat_normalize(firetalk_t conn, const char *const room) {
1974 return(firetalk_protocols[conn->protocol]->room_normalize(room));
1977 fte_t firetalk_set_away(firetalk_t conn, const char *const message, const int auto_flag) {
1978 VERIFYCONN;
1980 if (conn->connected == FCS_NOTCONNECTED)
1981 return(FE_NOTCONNECTED);
1983 return(firetalk_protocols[conn->protocol]->set_away(conn->handle, message, auto_flag));
1986 fte_t firetalk_set_nickname(firetalk_t conn, const char *const nickname) {
1987 VERIFYCONN;
1989 if (conn->connected == FCS_NOTCONNECTED)
1990 return(FE_NOTCONNECTED);
1992 return(firetalk_protocols[conn->protocol]->set_nickname(conn->handle, nickname));
1995 fte_t firetalk_set_password(firetalk_t conn, const char *const oldpass, const char *const newpass) {
1996 VERIFYCONN;
1998 if (conn->connected != FCS_ACTIVE)
1999 return(FE_NOTCONNECTED);
2001 return(firetalk_protocols[conn->protocol]->set_password(conn->handle, oldpass, newpass));
2004 fte_t firetalk_set_privacy(firetalk_t conn, const char *const mode) {
2005 VERIFYCONN;
2007 assert(mode != NULL);
2009 if (conn->connected == FCS_NOTCONNECTED)
2010 return(FE_NOTCONNECTED);
2012 return(firetalk_protocols[conn->protocol]->set_privacy(conn->handle, mode));
2015 fte_t firetalk_im_evil(firetalk_t conn, const char *const who) {
2016 VERIFYCONN;
2018 if (conn->connected != FCS_ACTIVE)
2019 return(FE_NOTCONNECTED);
2021 return(firetalk_protocols[conn->protocol]->im_evil(conn->handle, who));
2024 fte_t firetalk_chat_join(firetalk_t conn, const char *const room) {
2025 const char *normalroom;
2027 VERIFYCONN;
2029 if (conn->connected == FCS_NOTCONNECTED)
2030 return(FE_NOTCONNECTED);
2032 normalroom = firetalk_protocols[conn->protocol]->room_normalize(room);
2033 if (!normalroom)
2034 return(FE_ROOMUNAVAILABLE);
2036 return(firetalk_protocols[conn->protocol]->chat_join(conn->handle, normalroom));
2039 fte_t firetalk_chat_part(firetalk_t conn, const char *const room) {
2040 const char *normalroom;
2042 VERIFYCONN;
2044 if (conn->connected == FCS_NOTCONNECTED)
2045 return(FE_NOTCONNECTED);
2047 normalroom = firetalk_protocols[conn->protocol]->room_normalize(room);
2048 if (!normalroom)
2049 return(FE_ROOMUNAVAILABLE);
2051 return(firetalk_protocols[conn->protocol]->chat_part(conn->handle, normalroom));
2054 fte_t firetalk_chat_send_message(firetalk_t conn, const char *const room, const char *const message, const int auto_flag) {
2055 const char *normalroom;
2057 VERIFYCONN;
2059 if (conn->connected != FCS_ACTIVE)
2060 return(FE_NOTCONNECTED);
2062 if (*room == ':')
2063 normalroom = room;
2064 else
2065 normalroom = firetalk_protocols[conn->protocol]->room_normalize(room);
2066 if (!normalroom)
2067 return(FE_ROOMUNAVAILABLE);
2069 return(firetalk_protocols[conn->protocol]->chat_send_message(conn->handle, normalroom, message, auto_flag));
2072 fte_t firetalk_chat_send_action(firetalk_t conn, const char *const room, const char *const message, const int auto_flag) {
2073 const char *normalroom;
2075 VERIFYCONN;
2077 if (conn->connected != FCS_ACTIVE)
2078 return(FE_NOTCONNECTED);
2080 normalroom = firetalk_protocols[conn->protocol]->room_normalize(room);
2081 if (!normalroom)
2082 return(FE_ROOMUNAVAILABLE);
2084 return(firetalk_protocols[conn->protocol]->chat_send_action(conn->handle, normalroom, message, auto_flag));
2087 fte_t firetalk_chat_invite(firetalk_t conn, const char *const room, const char *const who, const char *const message) {
2088 const char *normalroom;
2090 VERIFYCONN;
2092 if (conn->connected != FCS_ACTIVE)
2093 return(FE_NOTCONNECTED);
2095 normalroom = firetalk_protocols[conn->protocol]->room_normalize(room);
2096 if (!normalroom)
2097 return(FE_ROOMUNAVAILABLE);
2099 return(firetalk_protocols[conn->protocol]->chat_invite(conn->handle, normalroom, who, message));
2102 fte_t firetalk_chat_set_topic(firetalk_t conn, const char *const room, const char *const topic) {
2103 const char *normalroom;
2105 VERIFYCONN;
2107 if (conn->connected != FCS_ACTIVE)
2108 return(FE_NOTCONNECTED);
2110 normalroom = firetalk_protocols[conn->protocol]->room_normalize(room);
2111 if (!normalroom)
2112 return(FE_ROOMUNAVAILABLE);
2114 return(firetalk_protocols[conn->protocol]->chat_set_topic(conn->handle, normalroom, topic));
2117 fte_t firetalk_chat_op(firetalk_t conn, const char *const room, const char *const who) {
2118 const char *normalroom;
2120 VERIFYCONN;
2122 if (conn->connected != FCS_ACTIVE)
2123 return(FE_NOTCONNECTED);
2125 normalroom = firetalk_protocols[conn->protocol]->room_normalize(room);
2126 if (!normalroom)
2127 return(FE_ROOMUNAVAILABLE);
2129 return(firetalk_protocols[conn->protocol]->chat_op(conn->handle, normalroom, who));
2132 fte_t firetalk_chat_deop(firetalk_t conn, const char *const room, const char *const who) {
2133 const char *normalroom;
2135 VERIFYCONN;
2137 if (conn->connected != FCS_ACTIVE)
2138 return(FE_NOTCONNECTED);
2140 normalroom = firetalk_protocols[conn->protocol]->room_normalize(room);
2141 if (!normalroom)
2142 return(FE_ROOMUNAVAILABLE);
2144 return(firetalk_protocols[conn->protocol]->chat_deop(conn->handle, normalroom, who));
2147 fte_t firetalk_chat_kick(firetalk_t conn, const char *const room, const char *const who, const char *const reason) {
2148 const char *normalroom;
2150 VERIFYCONN;
2152 if (conn->connected != FCS_ACTIVE)
2153 return(FE_NOTCONNECTED);
2155 normalroom = firetalk_protocols[conn->protocol]->room_normalize(room);
2156 if (!normalroom)
2157 return(FE_ROOMUNAVAILABLE);
2159 return(firetalk_protocols[conn->protocol]->chat_kick(conn->handle, normalroom, who, reason));
2162 fte_t firetalk_subcode_send_request(firetalk_t conn, const char *const to, const char *const command, const char *const args) {
2163 VERIFYCONN;
2165 if (conn->connected != FCS_ACTIVE)
2166 return(FE_NOTCONNECTED);
2168 // return(firetalk_protocols[conn->protocol]->subcode_send_request(conn->handle, to, command, args));
2169 firetalk_enqueue(&conn->subcode_requests, to, firetalk_protocols[conn->protocol]->subcode_encode(conn->handle, command, args));
2170 return(FE_SUCCESS);
2173 fte_t firetalk_subcode_send_reply(firetalk_t conn, const char *const to, const char *const command, const char *const args) {
2174 VERIFYCONN;
2176 if ((conn->connected != FCS_ACTIVE) && (*to != ':'))
2177 return(FE_NOTCONNECTED);
2179 // return(firetalk_protocols[conn->protocol]->subcode_send_reply(conn->handle, to, command, args));
2180 firetalk_enqueue(&conn->subcode_replies, to, firetalk_protocols[conn->protocol]->subcode_encode(conn->handle, command, args));
2181 return(FE_SUCCESS);
2184 fte_t firetalk_subcode_register_request_callback(firetalk_t conn, const char *const command, void (*callback)(firetalk_t, void *, const char *const, const char *const, const char *const)) {
2185 struct s_firetalk_subcode_callback *iter;
2187 VERIFYCONN;
2189 if (command == NULL) {
2190 if (conn->subcode_request_default)
2191 free(conn->subcode_request_default);
2192 conn->subcode_request_default = calloc(1, sizeof(struct s_firetalk_subcode_callback));
2193 if (conn->subcode_request_default == NULL)
2194 abort();
2195 conn->subcode_request_default->callback = (ptrtofnct)callback;
2196 } else {
2197 iter = conn->subcode_request_head;
2198 conn->subcode_request_head = calloc(1, sizeof(struct s_firetalk_subcode_callback));
2199 if (conn->subcode_request_head == NULL)
2200 abort();
2201 conn->subcode_request_head->next = iter;
2202 conn->subcode_request_head->command = strdup(command);
2203 if (conn->subcode_request_head->command == NULL)
2204 abort();
2205 conn->subcode_request_head->callback = (ptrtofnct)callback;
2207 return(FE_SUCCESS);
2210 fte_t firetalk_subcode_register_request_reply(firetalk_t conn, const char *const command, const char *const reply) {
2211 struct s_firetalk_subcode_callback *iter;
2213 VERIFYCONN;
2215 if (command == NULL) {
2216 if (conn->subcode_request_default)
2217 free(conn->subcode_request_default);
2218 conn->subcode_request_default = calloc(1, sizeof(struct s_firetalk_subcode_callback));
2219 if (conn->subcode_request_default == NULL)
2220 abort();
2221 conn->subcode_request_default->staticresp = strdup(reply);
2222 if (conn->subcode_request_default->staticresp == NULL)
2223 abort();
2224 } else {
2225 iter = conn->subcode_request_head;
2226 conn->subcode_request_head = calloc(1, sizeof(struct s_firetalk_subcode_callback));
2227 if (conn->subcode_request_head == NULL)
2228 abort();
2229 conn->subcode_request_head->next = iter;
2230 conn->subcode_request_head->command = strdup(command);
2231 if (conn->subcode_request_head->command == NULL)
2232 abort();
2233 conn->subcode_request_head->staticresp = strdup(reply);
2234 if (conn->subcode_request_head->staticresp == NULL)
2235 abort();
2237 return(FE_SUCCESS);
2240 fte_t firetalk_subcode_register_reply_callback(firetalk_t conn, const char *const command, void (*callback)(firetalk_t, void *, const char *const, const char *const, const char *const)) {
2241 struct s_firetalk_subcode_callback *iter;
2243 VERIFYCONN;
2245 if (command == NULL) {
2246 if (conn->subcode_reply_default)
2247 free(conn->subcode_reply_default);
2248 conn->subcode_reply_default = calloc(1, sizeof(struct s_firetalk_subcode_callback));
2249 if (conn->subcode_reply_default == NULL)
2250 abort();
2251 conn->subcode_reply_default->callback = (ptrtofnct)callback;
2252 } else {
2253 iter = conn->subcode_reply_head;
2254 conn->subcode_reply_head = calloc(1, sizeof(struct s_firetalk_subcode_callback));
2255 if (conn->subcode_reply_head == NULL)
2256 abort();
2257 conn->subcode_reply_head->next = iter;
2258 conn->subcode_reply_head->command = strdup(command);
2259 if (conn->subcode_reply_head->command == NULL)
2260 abort();
2261 conn->subcode_reply_head->callback = (ptrtofnct)callback;
2263 return(FE_SUCCESS);
2266 fte_t firetalk_file_offer(firetalk_t conn, const char *const nickname, const char *const filename, void *clientfilestruct) {
2267 struct s_firetalk_file *iter;
2268 struct stat s;
2269 struct sockaddr_in addr;
2270 char args[256];
2271 unsigned int l;
2273 VERIFYCONN;
2275 iter = conn->file_head;
2276 conn->file_head = calloc(1, sizeof(struct s_firetalk_file));
2277 if (conn->file_head == NULL)
2278 abort();
2279 conn->file_head->who = strdup(nickname);
2280 if (conn->file_head->who == NULL)
2281 abort();
2282 conn->file_head->filename = strdup(filename);
2283 if (conn->file_head->filename == NULL)
2284 abort();
2285 conn->file_head->sockfd = -1;
2286 conn->file_head->clientfilestruct = clientfilestruct;
2288 conn->file_head->filefd = open(filename, O_RDONLY);
2289 if (conn->file_head->filefd == -1) {
2290 firetalk_file_cancel(conn, conn->file_head);
2291 return(FE_IOERROR);
2294 if (fstat(conn->file_head->filefd, &s) != 0) {
2295 firetalk_file_cancel(conn, conn->file_head);
2296 return(FE_IOERROR);
2299 conn->file_head->size = (long)s.st_size;
2301 conn->file_head->sockfd = socket(PF_INET, SOCK_STREAM, 0);
2302 if (conn->file_head->sockfd == -1) {
2303 firetalk_file_cancel(conn, conn->file_head);
2304 return(FE_SOCKET);
2307 addr.sin_family = AF_INET;
2308 addr.sin_port = 0;
2309 addr.sin_addr.s_addr = INADDR_ANY;
2310 if (bind(conn->file_head->sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) != 0) {
2311 firetalk_file_cancel(conn, conn->file_head);
2312 return(FE_SOCKET);
2315 if (listen(conn->file_head->sockfd, 1) != 0) {
2316 firetalk_file_cancel(conn, conn->file_head);
2317 return(FE_SOCKET);
2320 l = (unsigned int)sizeof(struct sockaddr_in);
2321 if (getsockname(conn->file_head->sockfd, (struct sockaddr *)&addr, &l) != 0) {
2322 firetalk_file_cancel(conn, conn->file_head);
2323 return(FE_SOCKET);
2326 conn->file_head->bytes = 0;
2327 conn->file_head->state = FF_STATE_WAITREMOTE;
2328 conn->file_head->direction = FF_DIRECTION_SENDING;
2329 conn->file_head->port = ntohs(addr.sin_port);
2330 conn->file_head->next = iter;
2331 conn->file_head->type = FF_TYPE_DCC;
2332 snprintf(args, sizeof(args), "SEND %s %lu %u %ld", conn->file_head->filename, conn->localip, conn->file_head->port, conn->file_head->size);
2333 return(firetalk_subcode_send_request(conn, nickname, "DCC", args));
2336 fte_t firetalk_file_accept(firetalk_t conn, void *filehandle, void *clientfilestruct, const char *const localfile) {
2337 struct s_firetalk_file *fileiter;
2338 struct sockaddr_in addr;
2340 VERIFYCONN;
2342 fileiter = filehandle;
2343 fileiter->clientfilestruct = clientfilestruct;
2345 fileiter->filefd = open(localfile, O_WRONLY|O_CREAT|O_EXCL, S_IRWXU);
2346 if (fileiter->filefd == -1)
2347 return(FE_NOPERMS);
2349 addr.sin_family = AF_INET;
2350 addr.sin_port = fileiter->port;
2351 memcpy(&addr.sin_addr.s_addr, &fileiter->inet_ip, 4);
2352 fileiter->sockfd = firetalk_internal_connect(&addr
2353 #ifdef _FC_USE_IPV6
2354 , NULL
2355 #endif
2357 if (fileiter->sockfd == -1) {
2358 firetalk_file_cancel(conn, filehandle);
2359 return(FE_SOCKET);
2361 fileiter->state = FF_STATE_WAITSYNACK;
2362 return(FE_SUCCESS);
2365 fte_t firetalk_file_cancel(firetalk_t conn, void *filehandle) {
2366 struct s_firetalk_file *fileiter, *prev;
2368 VERIFYCONN;
2370 prev = NULL;
2371 for (fileiter = conn->file_head; fileiter != NULL; fileiter = fileiter->next) {
2372 if (fileiter == filehandle) {
2373 if (prev != NULL)
2374 prev->next = fileiter->next;
2375 else
2376 conn->file_head = fileiter->next;
2377 if (fileiter->who) {
2378 free(fileiter->who);
2379 fileiter->who = NULL;
2381 if (fileiter->filename) {
2382 free(fileiter->filename);
2383 fileiter->filename = NULL;
2385 if (fileiter->sockfd >= 0) {
2386 close(fileiter->sockfd);
2387 fileiter->sockfd = -1;
2389 if (fileiter->filefd >= 0) {
2390 close(fileiter->filefd);
2391 fileiter->filefd = -1;
2393 free(fileiter);
2394 return(FE_SUCCESS);
2396 prev = fileiter;
2398 return(FE_NOTFOUND);
2401 fte_t firetalk_file_refuse(firetalk_t conn, void *filehandle) {
2402 return(firetalk_file_cancel(conn, filehandle));
2405 fte_t firetalk_compare_nicks(firetalk_t conn, const char *const nick1, const char *const nick2) {
2406 VERIFYCONN;
2408 return(firetalk_protocols[conn->protocol]->comparenicks(nick1, nick2));
2411 fte_t firetalk_isprint(firetalk_t conn, const int c) {
2412 VERIFYCONN;
2414 return(firetalk_protocols[conn->protocol]->isprintable(c));
2417 fte_t firetalk_select() {
2418 return(firetalk_select_custom(0, NULL, NULL, NULL, NULL));
2421 fte_t firetalk_select_custom(int n, fd_set *fd_read, fd_set *fd_write, fd_set *fd_except, struct timeval *timeout) {
2422 int ret;
2423 fd_set *my_read, *my_write, *my_except;
2424 fd_set internal_read, internal_write, internal_except;
2425 struct timeval internal_timeout, *my_timeout;
2426 struct s_firetalk_handle *fchandle;
2428 my_read = fd_read;
2429 my_write = fd_write;
2430 my_except = fd_except;
2431 my_timeout = timeout;
2433 if (!my_read) {
2434 my_read = &internal_read;
2435 FD_ZERO(my_read);
2438 if (!my_write) {
2439 my_write = &internal_write;
2440 FD_ZERO(my_write);
2443 if (!my_except) {
2444 my_except = &internal_except;
2445 FD_ZERO(my_except);
2448 if (!my_timeout) {
2449 my_timeout = &internal_timeout;
2450 my_timeout->tv_sec = 15;
2451 my_timeout->tv_usec = 0;
2454 if (my_timeout->tv_sec > 15)
2455 my_timeout->tv_sec = 15;
2457 /* internal preselect */
2458 for (fchandle = handle_head; fchandle != NULL; fchandle = fchandle->next) {
2459 struct s_firetalk_file *fileiter;
2461 if (fchandle->deleted)
2462 continue;
2464 if (fchandle->connected == FCS_NOTCONNECTED)
2465 continue;
2467 while (fchandle->subcode_requests.count > 0) {
2468 int count = fchandle->subcode_requests.count;
2469 char *key = strdup(fchandle->subcode_requests.keys[0]);
2471 firetalk_protocols[fchandle->protocol]->im_send_message(fchandle->handle, key, "", 0);
2472 free(key);
2473 assert(fchandle->subcode_requests.count < count);
2476 while (fchandle->subcode_replies.count > 0) {
2477 int count = fchandle->subcode_replies.count;
2478 char *key = strdup(fchandle->subcode_replies.keys[0]);
2480 firetalk_protocols[fchandle->protocol]->im_send_message(fchandle->handle, key, "", 1);
2481 free(key);
2482 assert(fchandle->subcode_replies.count < count);
2485 firetalk_protocols[fchandle->protocol]->periodic(fchandle);
2486 if (fchandle->connected == FCS_NOTCONNECTED)
2487 continue;
2489 if (fchandle->fd >= n)
2490 n = fchandle->fd + 1;
2491 assert(fchandle->fd >= 0);
2492 FD_SET(fchandle->fd, my_except);
2493 if (fchandle->connected == FCS_WAITING_SYNACK)
2494 FD_SET(fchandle->fd, my_write);
2495 else
2496 FD_SET(fchandle->fd, my_read);
2498 for (fileiter = fchandle->file_head; fileiter != NULL; fileiter = fileiter->next) {
2499 if (fileiter->state == FF_STATE_TRANSFERRING) {
2500 if (fileiter->sockfd >= n)
2501 n = fileiter->sockfd + 1;
2502 switch (fileiter->direction) {
2503 case FF_DIRECTION_SENDING:
2504 assert(fileiter->sockfd >= 0);
2505 FD_SET(fileiter->sockfd, my_write);
2506 FD_SET(fileiter->sockfd, my_except);
2507 break;
2508 case FF_DIRECTION_RECEIVING:
2509 assert(fileiter->sockfd >= 0);
2510 FD_SET(fileiter->sockfd, my_read);
2511 FD_SET(fileiter->sockfd, my_except);
2512 break;
2514 } else if (fileiter->state == FF_STATE_WAITREMOTE) {
2515 assert(fileiter->sockfd >= 0);
2516 if (fileiter->sockfd >= n)
2517 n = fileiter->sockfd + 1;
2518 FD_SET(fileiter->sockfd, my_read);
2519 FD_SET(fileiter->sockfd, my_except);
2520 } else if (fileiter->state == FF_STATE_WAITSYNACK) {
2521 assert(fileiter->sockfd >= 0);
2522 if (fileiter->sockfd >= n)
2523 n = fileiter->sockfd + 1;
2524 FD_SET(fileiter->sockfd, my_write);
2525 FD_SET(fileiter->sockfd, my_except);
2530 /* per-protocol preselect, UI prepoll */
2531 for (fchandle = handle_head; fchandle != NULL; fchandle = fchandle->next) {
2532 if (fchandle->deleted)
2533 continue;
2534 firetalk_protocols[fchandle->protocol]->preselect(fchandle->handle, my_read, my_write, my_except, &n);
2535 if (fchandle->callbacks[FC_PRESELECT])
2536 fchandle->callbacks[FC_PRESELECT](fchandle, fchandle->clientstruct);
2539 /* select */
2540 if (n > 0) {
2541 ret = select(n, my_read, my_write, my_except, my_timeout);
2542 if (ret == -1)
2543 return(FE_PACKET);
2546 /* per-protocol postselect, UI postpoll */
2547 for (fchandle = handle_head; fchandle != NULL; fchandle = fchandle->next) {
2548 if (fchandle->deleted)
2549 continue;
2551 firetalk_protocols[fchandle->protocol]->postselect(fchandle->handle, my_read, my_write, my_except);
2552 if (fchandle->callbacks[FC_POSTSELECT])
2553 fchandle->callbacks[FC_POSTSELECT](fchandle, fchandle->clientstruct);
2556 /* internal postpoll */
2557 for (fchandle = handle_head; fchandle != NULL; fchandle = fchandle->next) {
2558 struct s_firetalk_file *fileiter, *filenext;
2560 if (fchandle->deleted)
2561 continue;
2563 if (fchandle->connected == FCS_NOTCONNECTED)
2564 continue;
2565 assert(fchandle->fd >= 0);
2566 if (FD_ISSET(fchandle->fd, my_except))
2567 firetalk_protocols[fchandle->protocol]->disconnect(fchandle->handle);
2568 else if (FD_ISSET(fchandle->fd, my_read)) {
2569 short length;
2571 /* read data into handle buffer */
2572 length = recv(fchandle->fd, &fchandle->buffer[fchandle->bufferpos], firetalk_protocols[fchandle->protocol]->default_buffersize - fchandle->bufferpos, MSG_DONTWAIT);
2574 if (length < 1)
2575 firetalk_callback_disconnect(fchandle->handle, FE_DISCONNECT);
2576 else {
2577 fchandle->bufferpos += length;
2578 if (fchandle->connected == FCS_ACTIVE)
2579 firetalk_protocols[fchandle->protocol]->got_data(fchandle->handle, fchandle->buffer, &fchandle->bufferpos);
2580 else
2581 firetalk_protocols[fchandle->protocol]->got_data_connecting(fchandle->handle, fchandle->buffer, &fchandle->bufferpos);
2582 if (fchandle->bufferpos == firetalk_protocols[fchandle->protocol]->default_buffersize)
2583 firetalk_callback_disconnect(fchandle->handle, FE_PACKETSIZE);
2585 } else if (FD_ISSET(fchandle->fd, my_write))
2586 firetalk_handle_synack(fchandle);
2588 for (fileiter = fchandle->file_head; fileiter != NULL; fileiter = filenext) {
2589 filenext = fileiter->next;
2590 if (fileiter->state == FF_STATE_TRANSFERRING) {
2591 assert(fileiter->sockfd >= 0);
2592 if (FD_ISSET(fileiter->sockfd, my_write))
2593 firetalk_handle_send(fchandle, fileiter);
2594 if ((fileiter->sockfd != -1) && FD_ISSET(fileiter->sockfd, my_read))
2595 firetalk_handle_receive(fchandle, fileiter);
2596 if ((fileiter->sockfd != -1) && FD_ISSET(fileiter->sockfd, my_except)) {
2597 if (fchandle->callbacks[FC_FILE_ERROR])
2598 fchandle->callbacks[FC_FILE_ERROR](fchandle, fchandle->clientstruct, fileiter, fileiter->clientfilestruct, FE_IOERROR);
2599 firetalk_file_cancel(fchandle, fileiter);
2601 } else if (fileiter->state == FF_STATE_WAITREMOTE) {
2602 assert(fileiter->sockfd >= 0);
2603 if (FD_ISSET(fileiter->sockfd, my_read)) {
2604 unsigned int l = sizeof(struct sockaddr_in);
2605 struct sockaddr_in addr;
2606 int s;
2608 s = accept(fileiter->sockfd, (struct sockaddr *)&addr, &l);
2609 if (s == -1) {
2610 if (fchandle->callbacks[FC_FILE_ERROR])
2611 fchandle->callbacks[FC_FILE_ERROR](fchandle, fchandle->clientstruct, fileiter, fileiter->clientfilestruct, FE_SOCKET);
2612 firetalk_file_cancel(fchandle, fileiter);
2613 } else {
2614 close(fileiter->sockfd);
2615 fileiter->sockfd = s;
2616 fileiter->state = FF_STATE_TRANSFERRING;
2617 if (fchandle->callbacks[FC_FILE_START])
2618 fchandle->callbacks[FC_FILE_START](fchandle, fchandle->clientstruct, fileiter, fileiter->clientfilestruct);
2620 } else if (FD_ISSET(fileiter->sockfd, my_except)) {
2621 if (fchandle->callbacks[FC_FILE_ERROR])
2622 fchandle->callbacks[FC_FILE_ERROR](fchandle, fchandle->clientstruct, fileiter, fileiter->clientfilestruct, FE_IOERROR);
2623 firetalk_file_cancel(fchandle, fileiter);
2625 } else if (fileiter->state == FF_STATE_WAITSYNACK) {
2626 assert(fileiter->sockfd >= 0);
2627 if (FD_ISSET(fileiter->sockfd, my_write))
2628 firetalk_handle_file_synack(fchandle, fileiter);
2629 if (FD_ISSET(fileiter->sockfd, my_except))
2630 firetalk_file_cancel(fchandle, fileiter);
2635 /* handle deleted connections */
2637 struct s_firetalk_handle *fchandleprev, *fchandlenext;
2639 fchandleprev = NULL;
2640 for (fchandle = handle_head; fchandle != NULL; fchandle = fchandlenext) {
2641 fchandlenext = fchandle->next;
2642 if (fchandle->deleted == 1) {
2643 assert(fchandle->handle == NULL);
2644 if (fchandle->buddy_head != NULL) {
2645 struct s_firetalk_buddy *iter, *iternext;
2647 for (iter = fchandle->buddy_head; iter != NULL; iter = iternext) {
2648 iternext = iter->next;
2649 if (iter->nickname != NULL) {
2650 free(iter->nickname);
2651 iter->nickname = NULL;
2653 if (iter->group != NULL) {
2654 free(iter->group);
2655 iter->group = NULL;
2657 if (iter->capabilities != NULL) {
2658 free(iter->capabilities);
2659 iter->capabilities = NULL;
2661 free(iter);
2663 fchandle->buddy_head = NULL;
2665 if (fchandle->deny_head != NULL) {
2666 struct s_firetalk_deny *iter, *iternext;
2668 for (iter = fchandle->deny_head; iter != NULL; iter = iternext) {
2669 iternext = iter->next;
2670 if (iter->nickname != NULL) {
2671 free(iter->nickname);
2672 iter->nickname = NULL;
2674 free(iter);
2676 fchandle->deny_head = NULL;
2678 if (fchandle->room_head != NULL) {
2679 struct s_firetalk_room *iter, *iternext;
2681 for (iter = fchandle->room_head; iter != NULL; iter = iternext) {
2682 struct s_firetalk_member *memberiter, *memberiternext;
2684 for (memberiter = iter->member_head; memberiter != NULL; memberiter = memberiternext) {
2685 memberiternext = memberiter->next;
2686 if (memberiter->nickname != NULL) {
2687 free(memberiter->nickname);
2688 memberiter->nickname = NULL;
2690 free(memberiter);
2692 iter->member_head = NULL;
2693 iternext = iter->next;
2694 if (iter->name != NULL) {
2695 free(iter->name);
2696 iter->name = NULL;
2698 free(iter);
2700 fchandle->room_head = NULL;
2702 if (fchandle->file_head != NULL) {
2703 struct s_firetalk_file *iter, *iternext;
2705 for (iter = fchandle->file_head; iter != NULL; iter = iternext) {
2706 iternext = iter->next;
2707 if (iter->who != NULL) {
2708 free(iter->who);
2709 iter->who = NULL;
2711 if (iter->filename != NULL) {
2712 free(iter->filename);
2713 iter->filename = NULL;
2715 free(iter);
2717 fchandle->file_head = NULL;
2719 if (fchandle->subcode_request_head != NULL) {
2720 struct s_firetalk_subcode_callback *iter, *iternext;
2722 for (iter = fchandle->subcode_request_head; iter != NULL; iter = iternext) {
2723 iternext = iter->next;
2724 if (iter->command != NULL) {
2725 free(iter->command);
2726 iter->command = NULL;
2728 if (iter->staticresp != NULL) {
2729 free(iter->staticresp);
2730 iter->staticresp = NULL;
2732 free(iter);
2734 fchandle->subcode_request_head = NULL;
2736 if (fchandle->subcode_request_default != NULL) {
2737 if (fchandle->subcode_request_default->command != NULL) {
2738 free(fchandle->subcode_request_default->command);
2739 fchandle->subcode_request_default->command = NULL;
2741 free(fchandle->subcode_request_default);
2742 fchandle->subcode_request_default = NULL;
2744 if (fchandle->subcode_reply_head != NULL) {
2745 struct s_firetalk_subcode_callback *iter, *iternext;
2747 for (iter = fchandle->subcode_reply_head; iter != NULL; iter = iternext) {
2748 iternext = iter->next;
2749 free(iter->command);
2750 free(iter);
2752 fchandle->subcode_reply_head = NULL;
2754 if (fchandle->subcode_reply_default != NULL) {
2755 if (fchandle->subcode_reply_default->command != NULL) {
2756 free(fchandle->subcode_reply_default->command);
2757 fchandle->subcode_reply_default->command = NULL;
2759 free(fchandle->subcode_reply_default);
2760 fchandle->subcode_reply_default = NULL;
2762 if (fchandle->username != NULL) {
2763 free(fchandle->username);
2764 fchandle->username = NULL;
2766 if (fchandle->buffer != NULL) {
2767 free(fchandle->buffer);
2768 fchandle->buffer = NULL;
2770 if (fchandleprev == NULL) {
2771 assert(fchandle == handle_head);
2772 handle_head = fchandlenext;
2773 } else {
2774 assert(fchandle != handle_head);
2775 fchandleprev->next = fchandlenext;
2778 free(fchandle);
2779 } else
2780 fchandleprev = fchandle;
2784 return(FE_SUCCESS);
2787 void firetalk_enqueue(firetalk_queue_t *queue, const char *const key, void *data) {
2788 queue->count++;
2789 queue->keys = realloc(queue->keys, (queue->count)*sizeof(*(queue->keys)));
2790 queue->data = realloc(queue->data, (queue->count)*sizeof(*(queue->data)));
2791 queue->keys[queue->count-1] = strdup(key);
2792 if (queue->keys[queue->count-1] == NULL)
2793 abort();
2794 queue->data[queue->count-1] = data;
2797 const void *firetalk_peek(firetalk_queue_t *queue, const char *const key) {
2798 int i;
2800 assert(queue != NULL);
2801 assert(key != NULL);
2803 for (i = 0; i < queue->count; i++)
2804 if (strcmp(queue->keys[i], key) == 0)
2805 return(queue->data[i]);
2806 return(NULL);
2809 void *firetalk_dequeue(firetalk_queue_t *queue, const char *const key) {
2810 int i;
2812 assert(queue != NULL);
2813 assert(key != NULL);
2815 for (i = 0; i < queue->count; i++)
2816 if (strcmp(queue->keys[i], key) == 0) {
2817 void *data = queue->data[i];
2819 free(queue->keys[i]);
2820 queue->keys[i] = NULL;
2821 memmove(queue->keys+i, queue->keys+i+1, (queue->count-i-1)*sizeof(*(queue->keys)));
2822 memmove(queue->data+i, queue->data+i+1, (queue->count-i-1)*sizeof(*(queue->data)));
2823 queue->count--;
2824 queue->keys = realloc(queue->keys, (queue->count)*sizeof(*(queue->keys)));
2825 queue->data = realloc(queue->data, (queue->count)*sizeof(*(queue->data)));
2826 return(data);
2828 return(NULL);
2831 void firetalk_queue_append(char *buf, int buflen, firetalk_queue_t *queue, const char *const key) {
2832 const char *data;
2834 while ((data = firetalk_peek(queue, key)) != NULL) {
2835 if (strlen(buf)+strlen(data) >= buflen-1)
2836 break;
2837 strcat(buf, data);
2838 free(firetalk_dequeue(queue, key));
2842 fte_t firetalk_im_searchemail(firetalk_t conn, const char * const email)
2844 if (conn->connected != FCS_ACTIVE)
2845 return FE_NOTCONNECTED;
2846 return firetalk_protocols[conn->protocol]->im_searchemail(conn->handle,email);
2849 fte_t firetalk_getsockets(const int prot, int **r, int **w, int **e) {
2850 struct s_firetalk_handle *fchandle;
2851 struct s_firetalk_file *fileiter;
2852 int rs, ws, es, *pr, *pw, *pe;
2854 pr = pw = pe = NULL;
2855 rs = ws = es = 0;
2857 #define wadd(fd) {pw = (int *) realloc(pw, (++ws)*sizeof(int)); pw[ws-1] = fd;}
2858 #define radd(fd) {pr = (int *) realloc(pr, (++rs)*sizeof(int)); pr[rs-1] = fd;}
2859 #define eadd(fd) {pe = (int *) realloc(pe, (++es)*sizeof(int)); pe[es-1] = fd;}
2861 fchandle = handle_head;
2863 while(fchandle) {
2864 if((fchandle->connected == FCS_NOTCONNECTED)
2865 || (fchandle->protocol != prot)) {
2866 fchandle = fchandle->next;
2867 } else {
2868 eadd(fchandle->fd);
2870 if(fchandle->connected == FCS_WAITING_SYNACK)
2871 wadd(fchandle->fd)
2872 else
2873 radd(fchandle->fd);
2875 fileiter = fchandle->file_head;
2876 while(fileiter) {
2877 if(fileiter->state == FF_STATE_TRANSFERRING) {
2878 switch(fileiter->direction) {
2879 case FF_DIRECTION_SENDING:
2880 wadd(fchandle->fd);
2881 eadd(fchandle->fd);
2882 break;
2884 case FF_DIRECTION_RECEIVING:
2885 radd(fchandle->fd);
2886 eadd(fchandle->fd);
2887 break;
2889 } else if(fileiter->state == FF_STATE_WAITREMOTE) {
2890 radd(fchandle->fd);
2891 eadd(fchandle->fd);
2893 } else if(fileiter->state == FF_STATE_WAITSYNACK) {
2894 wadd(fchandle->fd);
2895 eadd(fchandle->fd);
2897 fileiter = fileiter->next;
2900 fchandle = fchandle->next;
2904 radd(0);
2905 wadd(0);
2906 eadd(0);
2908 *r = pr, *w = pw, *e = pe;
2910 return FE_SUCCESS;