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
23 #include <sys/types.h>
27 #include <netinet/in.h>
28 #include <sys/socket.h>
29 #include <arpa/inet.h>
39 #include "firetalk-int.h"
42 typedef void (*ptrtotoc
)(void *, ...);
43 typedef void (*sighandler_t
)(int);
45 /* Global variables */
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
;
58 ptr
= realloc(firetalk_protocols
, sizeof(*firetalk_protocols
)*(FP_MAX
+1));
61 firetalk_protocols
= ptr
;
62 firetalk_protocols
[FP_MAX
++] = proto
;
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
)
73 if (firetalk_register_protocol(&firetalk_protocol_toc2
) != FE_SUCCESS
)
77 int firetalk_find_protocol(const char *strprotocol
) {
78 static int registered_defaults
= 0;
81 if (strprotocol
== NULL
)
84 for (i
= 0; i
< FP_MAX
; i
++)
85 if (strcasecmp(strprotocol
, firetalk_protocols
[i
]->strprotocol
) == 0)
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)
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
)
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
)
121 # define VERIFYCONN \
123 if (firetalk_check_handle(conn) != FE_SUCCESS) \
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
)
133 return(FE_BADHANDLE
);
136 # define VERIFYCONN \
141 static char **firetalk_parse_subcode_args(char *string
) {
142 static char *args
[256];
149 for (i
= 0; (size_t) i
< l
&& n
< 255; i
++) {
150 if (string
[i
] == ' ') {
152 args
[n
++] = &string
[i
];
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')));
167 return((unsigned char)62);
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]);
187 fte_t
firetalk_im_internal_add_deny(firetalk_t conn
, const char *const nickname
) {
188 struct s_firetalk_deny
*iter
;
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 */
197 iter
= conn
->deny_head
;
198 conn
->deny_head
= calloc(1, sizeof(struct s_firetalk_deny
));
199 if (conn
->deny_head
== NULL
)
201 conn
->deny_head
->next
= iter
;
202 conn
->deny_head
->nickname
= strdup(nickname
);
203 if (conn
->deny_head
->nickname
== NULL
)
207 firetalk_callback_im_buddyonline(conn
->handle
, nickname
, 0);
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
) {
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
));
241 FD_SET(pi
[0], &readset
);
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
))) {
257 fte_t
firetalk_internal_resolve4(const char *const host
, struct in_addr
*inet4_ip
) {
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
));
266 memset(&(inet4_ip
->s_addr
), 0, sizeof(inet4_ip
->s_addr
));
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
));
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);
295 memset(&(inet6_ip
->s6_addr
), 0, sizeof(inet6_ip
->s6_addr
));
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
));
311 int firetalk_internal_connect_host_addr(const char *const host
, const uint16_t port
, struct sockaddr_in
*inet4
313 , struct sockaddr_in6
*inet6
317 if (firetalk_internal_resolve6(host
, &(inet6
->sin6_addr
)) == FE_SUCCESS
) {
318 inet6
->sin6_port
= htons(port
);
319 inet6
->sin6_family
= AF_INET6
;
323 if (firetalk_internal_resolve4(host
, &(inet4
->sin_addr
)) == FE_SUCCESS
) {
324 inet4
->sin_port
= htons(port
);
325 inet4
->sin_family
= AF_INET
;
329 return firetalk_internal_connect(inet4
336 int firetalk_internal_connect_host(const char *const host
, const int port
) {
337 struct sockaddr_in myinet4
;
339 struct sockaddr_in6 myinet6
;
342 return(firetalk_internal_connect_host_addr(host
, port
, &myinet4
349 int firetalk_internal_connect(struct sockaddr_in
*inet4_ip
351 , struct sockaddr_in6
*inet6_ip
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])) {
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
))
375 if (inet4_ip
&& inet4_ip
->sin_addr
.s_addr
) {
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
))
385 firetalkerror
= FE_CONNECT
;
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
)
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
;
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
)
431 fte_t
firetalk_user_visible_but(firetalk_t conn
, const char *const room
, const char *const nickname
) {
432 struct s_firetalk_room
*iter
;
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
)
441 for (mem
= iter
->member_head
; mem
!= NULL
; mem
= mem
->next
)
442 if (firetalk_protocols
[conn
->protocol
]->comparenicks(mem
->nickname
, nickname
) == FE_SUCCESS
)
448 fte_t
firetalk_chat_internal_add_room(firetalk_t conn
, const char *const name
) {
449 struct s_firetalk_room
*iter
;
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
)
461 conn
->room_head
->next
= iter
;
462 conn
->room_head
->name
= strdup(name
);
463 if (conn
->room_head
->name
== NULL
)
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
;
475 for (iter
= conn
->room_head
; iter
!= NULL
; iter
= iter
->next
)
476 if (firetalk_protocols
[conn
->protocol
]->comparenicks(iter
->name
, room
) == FE_SUCCESS
)
479 if (iter
== NULL
) /* we don't know about that room */
482 for (memberiter
= iter
->member_head
; memberiter
!= NULL
; memberiter
= memberiter
->next
)
483 if (firetalk_protocols
[conn
->protocol
]->comparenicks(memberiter
->nickname
, nickname
) == FE_SUCCESS
)
486 memberiter
= iter
->member_head
;
487 iter
->member_head
= calloc(1, sizeof(struct s_firetalk_member
));
488 if (iter
->member_head
== NULL
)
490 iter
->member_head
->next
= memberiter
;
491 iter
->member_head
->nickname
= strdup(nickname
);
492 if (iter
->member_head
->nickname
== NULL
)
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
)
512 prev
->next
= iter
->next
;
514 conn
->buddy_head
= iter
->next
;
515 free(iter
->nickname
);
516 iter
->nickname
= 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
;
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
)
544 fte_t
firetalk_im_remove_buddy(firetalk_t conn
, const char *const name
) {
545 struct s_firetalk_buddy
*iter
;
549 if ((iter
= firetalk_im_find_buddy(conn
, name
)) == NULL
)
552 if (conn
->connected
!= FCS_NOTCONNECTED
) {
555 ret
= firetalk_protocols
[conn
->protocol
]->im_remove_buddy(conn
->handle
, iter
->nickname
, iter
->group
);
556 if (ret
!= FE_SUCCESS
)
560 firetalk_im_delete_buddy(conn
, name
);
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
;
572 for (iter
= conn
->deny_head
; iter
!= NULL
; iter
= iter
->next
) {
573 if (firetalk_protocols
[conn
->protocol
]->comparenicks(nickname
, iter
->nickname
) == FE_SUCCESS
) {
575 prev
->next
= iter
->next
;
577 conn
->deny_head
= iter
->next
;
578 free(iter
->nickname
);
579 iter
->nickname
= NULL
;
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
;
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
;
606 iter
->member_head
= NULL
;
608 prev
->next
= iter
->next
;
610 conn
->room_head
= iter
->next
;
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
;
631 for (iter
= conn
->room_head
; iter
!= NULL
; iter
= iter
->next
)
632 if (firetalk_protocols
[conn
->protocol
]->comparenicks(iter
->name
, room
) == FE_SUCCESS
)
635 if (iter
== NULL
) /* we don't know about that room */
639 for (memberiter
= iter
->member_head
; memberiter
!= NULL
; memberiter
= memberiter
->next
) {
640 if (firetalk_protocols
[conn
->protocol
]->comparenicks(memberiter
->nickname
,nickname
) == FE_SUCCESS
) {
642 memberprev
->next
= memberiter
->next
;
644 iter
->member_head
= memberiter
->next
;
645 if (memberiter
->nickname
) {
646 free(memberiter
->nickname
);
647 memberiter
->nickname
= NULL
;
652 memberprev
= memberiter
;
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
)
667 firetalkerror
= FE_NOTFOUND
;
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
)
678 firetalkerror
= FE_NOTFOUND
;
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
);
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
)
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
)
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
;
733 if ((buddyiter
= firetalk_im_find_buddy(conn
, nickname
)) != NULL
)
734 if (buddyiter
->online
!= online
) {
735 buddyiter
->online
= online
;
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
)
748 if (conn
->callbacks
[FC_IM_BUDDYONLINE
] != NULL
)
749 conn
->callbacks
[FC_IM_BUDDYONLINE
](conn
, conn
->clientstruct
, nickname
);
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
));
782 newiter
->next
= conn
->buddy_head
;
783 conn
->buddy_head
= newiter
;
784 newiter
->nickname
= strdup(name
);
785 if (newiter
->nickname
== NULL
)
787 newiter
->group
= strdup(group
);
788 if (newiter
->group
== NULL
)
790 if (friendly
== NULL
)
791 newiter
->friendly
= NULL
;
793 newiter
->friendly
= strdup(friendly
);
794 if (newiter
->friendly
== NULL
)
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
);
831 if (!conn
->callbacks
[FC_IM_TYPINGINFO
])
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
])
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
])
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
)
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
)
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
;
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
;
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
;
950 roomiter
->member_head
= NULL
;
951 free(roomiter
->name
);
952 roomiter
->name
= NULL
;
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
);
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
])
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
;
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
)
1051 if (conn
->callbacks
[FC_IM_USER_NICKCHANGED
])
1052 conn
->callbacks
[FC_IM_USER_NICKCHANGED
](conn
, conn
->clientstruct
, tempstr
, newnick
);
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
)
1064 if (conn
->callbacks
[FC_CHAT_USER_NICKCHANGED
])
1065 conn
->callbacks
[FC_CHAT_USER_NICKCHANGED
](conn
, conn
->clientstruct
, roomiter
->name
, tempstr
, newnick
);
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
)
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
)
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
)
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
);
1134 if (iter
->sentjoin
== 0) {
1136 if (conn
->callbacks
[FC_CHAT_JOINED
])
1137 conn
->callbacks
[FC_CHAT_JOINED
](conn
, conn
->clientstruct
, room
);
1140 if (firetalk_chat_internal_add_member(conn
, room
, who
) != FE_SUCCESS
)
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
)
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
);
1179 if (conn
->callbacks
[FC_CHAT_GOTTOPIC
])
1180 conn
->callbacks
[FC_CHAT_GOTTOPIC
](conn
, conn
->clientstruct
, room
, topic
, author
);
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
);
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
);
1202 m
= firetalk_find_member(conn
, r
, who
);
1205 if (m
->admin
== 0) {
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
);
1221 m
= firetalk_find_member(conn
, r
, who
);
1224 if (m
->admin
== 1) {
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
);
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
);
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
)
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
);
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
);
1306 isonline_hack
= from
;
1307 iter
->callback(conn
, conn
->clientstruct
, from
, command
, args
);
1308 isonline_hack
= NULL
;
1311 conn
->connected
= connectedsave
;
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) {
1325 firetalk_subcode_send_reply(conn
, from
, "PING", args
);
1327 firetalk_subcode_send_reply(conn
, from
, "PING", "");
1328 } else if (strcmp(command
, "TIME") == 0) {
1334 strncpy(tempbuf
, ctime(&temptime
), sizeof(tempbuf
)-1);
1335 tempbuf
[sizeof(tempbuf
)-1] = 0;
1336 s
= strlen(tempbuf
);
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)) {
1342 struct in_addr addr
;
1348 struct in6_addr addr6
;
1349 struct in6_addr
*sendaddr6
= NULL
;
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]);
1357 if (myargs
[4] != NULL
) {
1358 /* ipv6-enabled dcc */
1359 inet_pton(AF_INET6
,myargs
[4],&addr6
);
1364 sscanf(myargs
[1], "%lu", &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
;
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
)
1403 conn
->file_head
->who
= strdup(from
);
1404 if (conn
->file_head
->who
== NULL
)
1406 conn
->file_head
->filename
= strdup(filename
);
1407 if (conn
->file_head
->filename
== NULL
)
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
);
1425 conn
->file_head
->tryinet6
= 0;
1427 if (inet_pton(AF_INET6
, ip6string
, &conn
->file_head
->inet6_ip
) != 0)
1428 conn
->file_head
->tryinet6
= 1;
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
;
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
);
1447 filestruct
->bytes
+= 4096;
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
);
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
);
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];
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
);
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
) {
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
);
1505 filestruct
->bytes
+= s
;
1506 if (filestruct
->type
== FF_TYPE_DCC
) {
1507 while (filestruct
->acked
< (uint32_t)filestruct
->bytes
) {
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
);
1529 const char *firetalk_strerror(const fte_t e
) {
1534 return("Connection failed");
1536 return("Usernames do not match");
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");
1544 return("Invalid sequence number from server");
1546 return("Invalid frame type from server");
1548 return("Packet too long");
1550 return("Server problem; try again later");
1552 return("Unknown error");
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");
1560 return("Invalid username");
1562 return("Username not found in list");
1564 return("Server disconnected");
1566 return("Unable to create socket");
1568 return("Unable to resolve hostname");
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");
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");
1586 return("You have requested idle to be reset too fast");
1588 return("Invalid room name");
1590 return("Invalid message (too long?)");
1591 case FE_MESSAGETRUNCATED
:
1592 return("Message truncated");
1594 return("Invalid protocol");
1595 case FE_NOTCONNECTED
:
1596 return("Not connected");
1597 case FE_BADCONNECTION
:
1598 return("Invalid connection number");
1600 return("No permission to perform operation");
1601 case FE_NOCHANGEPASS
:
1602 return("Unable to change password");
1604 return("Room already in list");
1606 return("Input/output error");
1608 return("Invalid handle");
1610 return("Operation timed out");
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
;
1624 handle_head
= calloc(1, sizeof(*handle_head
));
1625 if (handle_head
== NULL
)
1627 handle_head
->buffer
= calloc(1, firetalk_protocols
[protocol
]->default_buffersize
);
1628 if (handle_head
->buffer
== NULL
)
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
) {
1641 assert(conn
->deleted
== 0);
1642 assert(conn
->handle
!= NULL
);
1644 firetalk_protocols
[conn
->protocol
]->destroy_handle(conn
->handle
);
1645 conn
->handle
= NULL
;
1649 fte_t
firetalk_disconnect(firetalk_t conn
) {
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
) {
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
)
1670 conn
->bufferpos
= 0;
1673 server
= firetalk_protocols
[conn
->protocol
]->default_server
;
1676 port
= firetalk_protocols
[conn
->protocol
]->default_port
;
1679 conn
->fd
= firetalk_internal_connect_host_addr(server
, port
, &(conn
->remote_addr
)
1681 , &(conn
->remote_addr6
)
1685 if (conn
->fd
!= -1) {
1686 conn
->connected
= FCS_WAITING_SYNACK
;
1689 return(firetalkerror
);
1692 fte_t
firetalk_handle_synack(firetalk_t conn
) {
1694 unsigned int o
= sizeof(int);
1696 if (getsockopt(conn
->fd
, SOL_SOCKET
, SO_ERROR
, &i
, &o
)) {
1698 conn
->connected
= FCS_NOTCONNECTED
;
1699 if (conn
->callbacks
[FC_CONNECTFAILED
])
1700 conn
->callbacks
[FC_CONNECTFAILED
](conn
, conn
->clientstruct
, FE_SOCKET
, strerror(errno
));
1706 conn
->connected
= FCS_NOTCONNECTED
;
1707 if (conn
->callbacks
[FC_CONNECTFAILED
])
1708 conn
->callbacks
[FC_CONNECTFAILED
](conn
, conn
->clientstruct
, FE_CONNECT
, strerror(i
));
1712 conn
->connected
= FCS_WAITING_SIGNON
;
1713 i
= firetalk_protocols
[conn
->protocol
]->signon(conn
->handle
, conn
->username
);
1714 if (i
!= FE_SUCCESS
)
1720 void firetalk_callback_connected(client_t c
) {
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
) {
1738 unsigned int o
= sizeof(int);
1740 if (getsockopt(file
->sockfd
, SOL_SOCKET
, SO_ERROR
, &i
, &o
)) {
1741 firetalk_file_cancel(conn
, file
);
1746 firetalk_file_cancel(conn
, file
);
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
);
1757 enum firetalk_protocol
firetalk_get_protocol(firetalk_t conn
) {
1760 return(conn
->protocol
);
1763 fte_t
firetalk_register_callback(firetalk_t conn
, const int type
, void (*function
)(firetalk_t
, void *, ...)) {
1766 if (type
< 0 || type
>= FC_MAX
)
1767 return(FE_CALLBACKNUM
);
1768 conn
->callbacks
[type
] = function
;
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
;
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
) {
1783 ret
= firetalk_protocols
[conn
->protocol
]->im_remove_buddy(conn
->handle
, iter
->nickname
, iter
->group
);
1784 if (ret
!= FE_SUCCESS
)
1788 iter
->group
= strdup(group
);
1789 if (iter
->group
== NULL
)
1791 free(iter
->friendly
);
1792 if (friendly
== NULL
)
1793 iter
->friendly
= NULL
;
1795 iter
->friendly
= strdup(friendly
);
1796 if (iter
->friendly
== NULL
)
1801 firetalk_im_insert_buddy(conn
, name
, group
, friendly
);
1803 if (conn
->connected
!= FCS_NOTCONNECTED
) {
1806 ret
= firetalk_protocols
[conn
->protocol
]->im_add_buddy(conn
->handle
, name
, group
, friendly
);
1807 if (ret
!= FE_SUCCESS
)
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);
1817 fte_t
firetalk_im_add_deny(firetalk_t conn
, const char *const nickname
) {
1822 if (conn
->connected
!= FCS_ACTIVE
)
1823 return(FE_NOTCONNECTED
);
1825 ret
= firetalk_im_internal_add_deny(conn
,nickname
);
1826 if (ret
!= FE_SUCCESS
)
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
) {
1837 if (conn
->connected
!= FCS_ACTIVE
)
1838 return(FE_NOTCONNECTED
);
1840 ret
= firetalk_im_internal_remove_deny(conn
,nickname
);
1841 if (ret
!= FE_SUCCESS
)
1844 return(firetalk_protocols
[conn
->protocol
]->im_remove_deny(conn
->handle
,nickname
));
1847 fte_t
firetalk_im_upload_buddies(firetalk_t conn
) {
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
) {
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
);
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
) {
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
)
1890 e
= firetalk_protocols
[conn
->protocol
]->periodic(conn
);
1891 if (e
!= FE_SUCCESS
&& e
!= FE_IDLEFAST
)
1897 fte_t
firetalk_im_send_action(firetalk_t conn
, const char *const dest
, const char *const message
, const int auto_flag
) {
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
)
1909 e
= firetalk_protocols
[conn
->protocol
]->periodic(conn
);
1910 if (e
!= FE_SUCCESS
&& e
!= FE_IDLEFAST
)
1916 fte_t
firetalk_im_get_info(firetalk_t conn
, const char *const nickname
) {
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
) {
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
;
1939 if (conn
->connected
!= FCS_ACTIVE
)
1940 return(FE_NOTCONNECTED
);
1942 if (!conn
->callbacks
[FC_IM_LISTBUDDY
])
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
);
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
;
1957 if (conn
->connected
!= FCS_ACTIVE
)
1958 return(FE_NOTCONNECTED
);
1960 if (!conn
->callbacks
[FC_CHAT_LISTMEMBER
])
1963 room
= firetalk_find_room(conn
, roomname
);
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
);
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
) {
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
) {
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
) {
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
) {
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
) {
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
;
2029 if (conn
->connected
== FCS_NOTCONNECTED
)
2030 return(FE_NOTCONNECTED
);
2032 normalroom
= firetalk_protocols
[conn
->protocol
]->room_normalize(room
);
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
;
2044 if (conn
->connected
== FCS_NOTCONNECTED
)
2045 return(FE_NOTCONNECTED
);
2047 normalroom
= firetalk_protocols
[conn
->protocol
]->room_normalize(room
);
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
;
2059 if (conn
->connected
!= FCS_ACTIVE
)
2060 return(FE_NOTCONNECTED
);
2065 normalroom
= firetalk_protocols
[conn
->protocol
]->room_normalize(room
);
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
;
2077 if (conn
->connected
!= FCS_ACTIVE
)
2078 return(FE_NOTCONNECTED
);
2080 normalroom
= firetalk_protocols
[conn
->protocol
]->room_normalize(room
);
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
;
2092 if (conn
->connected
!= FCS_ACTIVE
)
2093 return(FE_NOTCONNECTED
);
2095 normalroom
= firetalk_protocols
[conn
->protocol
]->room_normalize(room
);
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
;
2107 if (conn
->connected
!= FCS_ACTIVE
)
2108 return(FE_NOTCONNECTED
);
2110 normalroom
= firetalk_protocols
[conn
->protocol
]->room_normalize(room
);
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
;
2122 if (conn
->connected
!= FCS_ACTIVE
)
2123 return(FE_NOTCONNECTED
);
2125 normalroom
= firetalk_protocols
[conn
->protocol
]->room_normalize(room
);
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
;
2137 if (conn
->connected
!= FCS_ACTIVE
)
2138 return(FE_NOTCONNECTED
);
2140 normalroom
= firetalk_protocols
[conn
->protocol
]->room_normalize(room
);
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
;
2152 if (conn
->connected
!= FCS_ACTIVE
)
2153 return(FE_NOTCONNECTED
);
2155 normalroom
= firetalk_protocols
[conn
->protocol
]->room_normalize(room
);
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
) {
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
));
2173 fte_t
firetalk_subcode_send_reply(firetalk_t conn
, const char *const to
, const char *const command
, const char *const args
) {
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
));
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
;
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
)
2195 conn
->subcode_request_default
->callback
= (ptrtofnct
)callback
;
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
)
2201 conn
->subcode_request_head
->next
= iter
;
2202 conn
->subcode_request_head
->command
= strdup(command
);
2203 if (conn
->subcode_request_head
->command
== NULL
)
2205 conn
->subcode_request_head
->callback
= (ptrtofnct
)callback
;
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
;
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
)
2221 conn
->subcode_request_default
->staticresp
= strdup(reply
);
2222 if (conn
->subcode_request_default
->staticresp
== NULL
)
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
)
2229 conn
->subcode_request_head
->next
= iter
;
2230 conn
->subcode_request_head
->command
= strdup(command
);
2231 if (conn
->subcode_request_head
->command
== NULL
)
2233 conn
->subcode_request_head
->staticresp
= strdup(reply
);
2234 if (conn
->subcode_request_head
->staticresp
== NULL
)
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
;
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
)
2251 conn
->subcode_reply_default
->callback
= (ptrtofnct
)callback
;
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
)
2257 conn
->subcode_reply_head
->next
= iter
;
2258 conn
->subcode_reply_head
->command
= strdup(command
);
2259 if (conn
->subcode_reply_head
->command
== NULL
)
2261 conn
->subcode_reply_head
->callback
= (ptrtofnct
)callback
;
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
;
2269 struct sockaddr_in addr
;
2275 iter
= conn
->file_head
;
2276 conn
->file_head
= calloc(1, sizeof(struct s_firetalk_file
));
2277 if (conn
->file_head
== NULL
)
2279 conn
->file_head
->who
= strdup(nickname
);
2280 if (conn
->file_head
->who
== NULL
)
2282 conn
->file_head
->filename
= strdup(filename
);
2283 if (conn
->file_head
->filename
== NULL
)
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
);
2294 if (fstat(conn
->file_head
->filefd
, &s
) != 0) {
2295 firetalk_file_cancel(conn
, conn
->file_head
);
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
);
2307 addr
.sin_family
= AF_INET
;
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
);
2315 if (listen(conn
->file_head
->sockfd
, 1) != 0) {
2316 firetalk_file_cancel(conn
, conn
->file_head
);
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
);
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
;
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)
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
2357 if (fileiter
->sockfd
== -1) {
2358 firetalk_file_cancel(conn
, filehandle
);
2361 fileiter
->state
= FF_STATE_WAITSYNACK
;
2365 fte_t
firetalk_file_cancel(firetalk_t conn
, void *filehandle
) {
2366 struct s_firetalk_file
*fileiter
, *prev
;
2371 for (fileiter
= conn
->file_head
; fileiter
!= NULL
; fileiter
= fileiter
->next
) {
2372 if (fileiter
== filehandle
) {
2374 prev
->next
= fileiter
->next
;
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;
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
) {
2408 return(firetalk_protocols
[conn
->protocol
]->comparenicks(nick1
, nick2
));
2411 fte_t
firetalk_isprint(firetalk_t conn
, const int c
) {
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
) {
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
;
2429 my_write
= fd_write
;
2430 my_except
= fd_except
;
2431 my_timeout
= timeout
;
2434 my_read
= &internal_read
;
2439 my_write
= &internal_write
;
2444 my_except
= &internal_except
;
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
)
2464 if (fchandle
->connected
== FCS_NOTCONNECTED
)
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);
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);
2482 assert(fchandle
->subcode_replies
.count
< count
);
2485 firetalk_protocols
[fchandle
->protocol
]->periodic(fchandle
);
2486 if (fchandle
->connected
== FCS_NOTCONNECTED
)
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
);
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
);
2508 case FF_DIRECTION_RECEIVING
:
2509 assert(fileiter
->sockfd
>= 0);
2510 FD_SET(fileiter
->sockfd
, my_read
);
2511 FD_SET(fileiter
->sockfd
, my_except
);
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
)
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
);
2541 ret
= select(n
, my_read
, my_write
, my_except
, my_timeout
);
2546 /* per-protocol postselect, UI postpoll */
2547 for (fchandle
= handle_head
; fchandle
!= NULL
; fchandle
= fchandle
->next
) {
2548 if (fchandle
->deleted
)
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
)
2563 if (fchandle
->connected
== FCS_NOTCONNECTED
)
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
)) {
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
);
2575 firetalk_callback_disconnect(fchandle
->handle
, FE_DISCONNECT
);
2577 fchandle
->bufferpos
+= length
;
2578 if (fchandle
->connected
== FCS_ACTIVE
)
2579 firetalk_protocols
[fchandle
->protocol
]->got_data(fchandle
->handle
, fchandle
->buffer
, &fchandle
->bufferpos
);
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
;
2608 s
= accept(fileiter
->sockfd
, (struct sockaddr
*)&addr
, &l
);
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
);
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
) {
2657 if (iter
->capabilities
!= NULL
) {
2658 free(iter
->capabilities
);
2659 iter
->capabilities
= NULL
;
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
;
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
;
2692 iter
->member_head
= NULL
;
2693 iternext
= iter
->next
;
2694 if (iter
->name
!= NULL
) {
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
) {
2711 if (iter
->filename
!= NULL
) {
2712 free(iter
->filename
);
2713 iter
->filename
= NULL
;
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
;
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
);
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
;
2774 assert(fchandle
!= handle_head
);
2775 fchandleprev
->next
= fchandlenext
;
2780 fchandleprev
= fchandle
;
2787 void firetalk_enqueue(firetalk_queue_t
*queue
, const char *const key
, void *data
) {
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
)
2794 queue
->data
[queue
->count
-1] = data
;
2797 const void *firetalk_peek(firetalk_queue_t
*queue
, const char *const key
) {
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
]);
2809 void *firetalk_dequeue(firetalk_queue_t
*queue
, const char *const key
) {
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
)));
2824 queue
->keys
= realloc(queue
->keys
, (queue
->count
)*sizeof(*(queue
->keys
)));
2825 queue
->data
= realloc(queue
->data
, (queue
->count
)*sizeof(*(queue
->data
)));
2831 void firetalk_queue_append(char *buf
, int buflen
, firetalk_queue_t
*queue
, const char *const key
) {
2834 while ((data
= firetalk_peek(queue
, key
)) != NULL
) {
2835 if (strlen(buf
)+strlen(data
) >= buflen
-1)
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
;
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
;
2864 if((fchandle
->connected
== FCS_NOTCONNECTED
)
2865 || (fchandle
->protocol
!= prot
)) {
2866 fchandle
= fchandle
->next
;
2870 if(fchandle
->connected
== FCS_WAITING_SYNACK
)
2875 fileiter
= fchandle
->file_head
;
2877 if(fileiter
->state
== FF_STATE_TRANSFERRING
) {
2878 switch(fileiter
->direction
) {
2879 case FF_DIRECTION_SENDING
:
2884 case FF_DIRECTION_RECEIVING
:
2889 } else if(fileiter
->state
== FF_STATE_WAITREMOTE
) {
2893 } else if(fileiter
->state
== FF_STATE_WAITSYNACK
) {
2897 fileiter
= fileiter
->next
;
2900 fchandle
= fchandle
->next
;
2908 *r
= pr
, *w
= pw
, *e
= pe
;