1 /* $Id: dcc.c,v 1.1 2004/01/26 23:49:33 konst Exp $ */
4 * (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl>
5 * Tomasz Chiliñski <chilek@chilan.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License Version
9 * 2.1 as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include <sys/types.h>
23 #include <sys/ioctl.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
28 # include <sys/filio.h>
43 #ifndef GG_DEBUG_DISABLE
45 * gg_dcc_debug_data() // funkcja wewnêtrzna
47 * wy¶wietla zrzut pakietu w hexie.
49 * - prefix - prefiks zrzutu pakietu
50 * - fd - deskryptor gniazda
51 * - buf - bufor z danymi
52 * - size - rozmiar danych
54 static void gg_dcc_debug_data(const char *prefix
, int fd
, const void *buf
, unsigned int size
)
58 gg_debug(GG_DEBUG_MISC
, "++ gg_dcc %s (fd=%d,len=%d)", prefix
, fd
, size
);
60 for (i
= 0; i
< size
; i
++)
61 gg_debug(GG_DEBUG_MISC
, " %.2x", ((unsigned char*) buf
)[i
]);
63 gg_debug(GG_DEBUG_MISC
, "\n");
66 #define gg_dcc_debug_data(a,b,c,d) do { } while (0)
72 * wysy³a informacjê o tym, ¿e dany klient powinien siê z nami po³±czyæ.
73 * wykorzystywane, kiedy druga strona, której chcemy co¶ wys³aæ jest za
76 * - sess - struktura opisuj±ca sesjê GG
77 * - uin - numerek odbiorcy
79 * patrz gg_send_message_ctcp().
81 int gg_dcc_request(struct gg_session
*sess
, uin_t uin
)
83 return gg_send_message_ctcp(sess
, GG_CLASS_CTCP
, uin
, "\002", 1);
87 * gg_dcc_fill_filetime() // funkcja wewnêtrzna
89 * zamienia czas w postaci unixowej na windowsowy.
91 * - unix - czas w postaci unixowej
92 * - filetime - czas w postaci windowsowej
94 void gg_dcc_fill_filetime(uint32_t ut
, uint32_t *ft
)
96 #ifdef __GG_LIBGADU_HAVE_LONG_LONG
97 unsigned long long tmp
;
100 tmp
+= 11644473600LL;
103 #ifndef __GG_LIBGADU_BIGENDIAN
104 ft
[0] = (uint32_t) tmp
;
105 ft
[1] = (uint32_t) (tmp
>> 32);
107 ft
[0] = gg_fix32((uint32_t) (tmp
>> 32));
108 ft
[1] = gg_fix32((uint32_t) tmp
);
115 * gg_dcc_fill_file_info()
117 * wype³nia pola struct gg_dcc niezbêdne do wys³ania pliku.
119 * - d - struktura opisuj±ca po³±czenie DCC
120 * - filename - nazwa pliku
124 int gg_dcc_fill_file_info(struct gg_dcc
*d
, const char *filename
)
127 const char *name
, *ext
, *p
;
130 gg_debug(GG_DEBUG_FUNCTION
, "** gg_dcc_fill_file_info(%p, \"%s\");\n", d
, filename
);
132 if (!d
|| d
->type
!= GG_SESSION_DCC_SEND
) {
133 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_fill_file_info() invalid arguments\n");
138 if (stat(filename
, &st
) == -1) {
139 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_fill_file_info() stat() failed (%s)\n", strerror(errno
));
143 if ((st
.st_mode
& S_IFDIR
)) {
144 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_fill_file_info() that's a directory\n");
149 if ((d
->file_fd
= open(filename
, O_RDONLY
)) == -1) {
150 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_fill_file_info() open() failed (%s)\n", strerror(errno
));
154 memset(&d
->file_info
, 0, sizeof(d
->file_info
));
156 if (!(st
.st_mode
& S_IWUSR
))
157 d
->file_info
.mode
|= gg_fix32(GG_DCC_FILEATTR_READONLY
);
159 gg_dcc_fill_filetime(st
.st_atime
, d
->file_info
.atime
);
160 gg_dcc_fill_filetime(st
.st_mtime
, d
->file_info
.mtime
);
161 gg_dcc_fill_filetime(st
.st_ctime
, d
->file_info
.ctime
);
163 d
->file_info
.size
= gg_fix32(st
.st_size
);
164 d
->file_info
.mode
= gg_fix32(0x20); /* FILE_ATTRIBUTE_ARCHIVE */
166 if (!(name
= strrchr(filename
, '/')))
171 if (!(ext
= strrchr(name
, '.')))
172 ext
= name
+ strlen(name
);
174 for (i
= 0, p
= name
; i
< 8 && p
< ext
; i
++, p
++)
175 d
->file_info
.short_filename
[i
] = toupper(name
[i
]);
177 if (strlen(ext
) > 0) {
178 for (j
= 0; *ext
&& j
< 4; j
++, p
++)
179 d
->file_info
.short_filename
[i
+ j
] = toupper(ext
[j
]);
183 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_fill_file_info() short name \"%s\", dos name \"%s\"\n", name
, d
->file_info
.short_filename
);
184 strncpy(d
->file_info
.filename
, name
, sizeof(d
->file_info
.filename
) - 1);
190 * gg_dcc_transfer() // funkcja wewnêtrzna
192 * inicjuje proces wymiany pliku z danym klientem.
194 * - ip - adres ip odbiorcy
195 * - port - port odbiorcy
196 * - my_uin - w³asny numer
197 * - peer_uin - numer obiorcy
198 * - type - rodzaj wymiany (GG_SESSION_DCC_SEND lub GG_SESSION_DCC_GET)
200 * zaalokowana struct gg_dcc lub NULL je¶li wyst±pi³ b³±d.
202 static struct gg_dcc
*gg_dcc_transfer(uint32_t ip
, uint16_t port
, uin_t my_uin
, uin_t peer_uin
, int type
)
204 struct gg_dcc
*d
= NULL
;
209 gg_debug(GG_DEBUG_FUNCTION
, "** gg_dcc_transfer(%s, %d, %ld, %ld, %s);\n", inet_ntoa(addr
), port
, my_uin
, peer_uin
, (type
== GG_SESSION_DCC_SEND
) ? "SEND" : "GET");
211 if (!ip
|| ip
== INADDR_NONE
|| !port
|| !my_uin
|| !peer_uin
) {
212 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_transfer() invalid arguments\n");
217 if (!(d
= (void*) calloc(1, sizeof(*d
)))) {
218 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_transfer() not enough memory\n");
222 d
->check
= GG_CHECK_WRITE
;
223 d
->state
= GG_STATE_CONNECTING
;
225 d
->timeout
= GG_DEFAULT_TIMEOUT
;
230 d
->peer_uin
= peer_uin
;
232 if ((d
->fd
= gg_connect(&addr
, port
, 1)) == -1) {
233 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_transfer() connection failed\n");
244 * inicjuje proces odbierania pliku od danego klienta, gdy ten wys³a³ do
245 * nas ¿±danie po³±czenia.
247 * - ip - adres ip odbiorcy
248 * - port - port odbiorcy
249 * - my_uin - w³asny numer
250 * - peer_uin - numer obiorcy
252 * zaalokowana struct gg_dcc lub NULL je¶li wyst±pi³ b³±d.
254 struct gg_dcc
*gg_dcc_get_file(uint32_t ip
, uint16_t port
, uin_t my_uin
, uin_t peer_uin
)
256 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_get_file() handing over to gg_dcc_transfer()\n");
258 return gg_dcc_transfer(ip
, port
, my_uin
, peer_uin
, GG_SESSION_DCC_GET
);
264 * inicjuje proces wysy³ania pliku do danego klienta.
266 * - ip - adres ip odbiorcy
267 * - port - port odbiorcy
268 * - my_uin - w³asny numer
269 * - peer_uin - numer obiorcy
271 * zaalokowana struct gg_dcc lub NULL je¶li wyst±pi³ b³±d.
273 struct gg_dcc
*gg_dcc_send_file(uint32_t ip
, uint16_t port
, uin_t my_uin
, uin_t peer_uin
)
275 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_send_file() handing over to gg_dcc_transfer()\n");
277 return gg_dcc_transfer(ip
, port
, my_uin
, peer_uin
, GG_SESSION_DCC_SEND
);
281 * gg_dcc_voice_chat()
283 * próbuje nawi±zaæ po³±czenie g³osowe.
285 * - ip - adres ip odbiorcy
286 * - port - port odbiorcy
287 * - my_uin - w³asny numer
288 * - peer_uin - numer obiorcy
290 * zaalokowana struct gg_dcc lub NULL je¶li wyst±pi³ b³±d.
292 struct gg_dcc
*gg_dcc_voice_chat(uint32_t ip
, uint16_t port
, uin_t my_uin
, uin_t peer_uin
)
294 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_voice_chat() handing over to gg_dcc_transfer()\n");
296 return gg_dcc_transfer(ip
, port
, my_uin
, peer_uin
, GG_SESSION_DCC_VOICE
);
302 * po zdarzeniu GG_EVENT_DCC_CALLBACK nale¿y ustawiæ typ po³±czenia za
303 * pomoc± tej funkcji.
305 * - d - struktura opisuj±ca po³±czenie
306 * - type - typ po³±czenia (GG_SESSION_DCC_SEND lub GG_SESSION_DCC_VOICE)
308 void gg_dcc_set_type(struct gg_dcc
*d
, int type
)
311 d
->state
= (type
== GG_SESSION_DCC_SEND
) ? GG_STATE_SENDING_FILE_INFO
: GG_STATE_SENDING_VOICE_REQUEST
;
315 * gg_dcc_callback() // funkcja wewnêtrzna
317 * wywo³ywana z struct gg_dcc->callback, odpala gg_dcc_watch_fd i umieszcza
318 * rezultat w struct gg_dcc->event.
320 * - d - structura opisuj±ca po³±czenie
324 static int gg_dcc_callback(struct gg_dcc
*d
)
326 struct gg_event
*e
= gg_dcc_watch_fd(d
);
330 return (e
!= NULL
) ? 0 : -1;
334 * gg_dcc_socket_create()
336 * tworzy gniazdo dla bezpo¶redniej komunikacji miêdzy klientami.
338 * - uin - w³asny numer
339 * - port - preferowany port, je¶li równy 0 lub -1, próbuje domy¶lnego
341 * zaalokowana struct gg_dcc, któr± po¼niej nale¿y zwolniæ funkcj±
342 * gg_dcc_free(), albo NULL je¶li wyst±pi³ b³±d.
344 struct gg_dcc
*gg_dcc_socket_create(uin_t uin
, uint16_t port
)
347 struct sockaddr_in sin
;
350 gg_debug(GG_DEBUG_FUNCTION
, "** gg_create_dcc_socket(%d, %d);\n", uin
, port
);
353 gg_debug(GG_DEBUG_MISC
, "// gg_create_dcc_socket() invalid arguments\n");
358 if ((sock
= socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
)) == -1) {
359 gg_debug(GG_DEBUG_MISC
, "// gg_create_dcc_socket() can't create socket (%s)\n", strerror(errno
));
364 port
= GG_DEFAULT_DCC_PORT
;
367 sin
.sin_family
= AF_INET
;
368 sin
.sin_addr
.s_addr
= INADDR_ANY
;
369 sin
.sin_port
= htons(port
);
371 gg_debug(GG_DEBUG_MISC
, "// gg_create_dcc_socket() trying port %d\n", port
);
372 if (!bind(sock
, (struct sockaddr
*) &sin
, sizeof(sin
)))
375 if (++port
== 65535) {
376 gg_debug(GG_DEBUG_MISC
, "// gg_create_dcc_socket() no free port found\n");
382 if (listen(sock
, 10)) {
383 gg_debug(GG_DEBUG_MISC
, "// gg_create_dcc_socket() unable to listen (%s)\n", strerror(errno
));
387 gg_debug(GG_DEBUG_MISC
, "// gg_create_dcc_socket() bound to port %d\n", port
);
389 if (!(c
= malloc(sizeof(*c
)))) {
390 gg_debug(GG_DEBUG_MISC
, "// gg_create_dcc_socket() not enough memory for struct\n");
394 memset(c
, 0, sizeof(*c
));
396 c
->port
= c
->id
= port
;
398 c
->type
= GG_SESSION_DCC_SOCKET
;
401 c
->state
= GG_STATE_LISTENING
;
402 c
->check
= GG_CHECK_READ
;
403 c
->callback
= gg_dcc_callback
;
404 c
->destroy
= gg_dcc_free
;
406 gg_dcc_ip
= INADDR_ANY
;
411 * gg_dcc_voice_send()
413 * wysy³a ramkê danych dla rozmowy g³osowej.
415 * - d - struktura opisuj±ca po³±czenie dcc
416 * - buf - bufor z danymi
417 * - length - rozmiar ramki
421 int gg_dcc_voice_send(struct gg_dcc
*d
, char *buf
, int length
)
427 struct packet_s packet
;
429 gg_debug(GG_DEBUG_FUNCTION
, "++ gg_dcc_voice_send(%p, %p, %d);\n", d
, buf
, length
);
430 if (!d
|| !buf
|| length
< 0 || d
->type
!= GG_SESSION_DCC_VOICE
) {
431 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_voice_send() invalid argument\n");
435 packet
.type
= 0x03; /* XXX */
436 packet
.length
= gg_fix32(length
);
438 if (write(d
->fd
, &packet
, sizeof(packet
)) < (signed)sizeof(packet
)) {
439 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_voice_send() write() failed\n");
442 gg_dcc_debug_data("write", d
->fd
, &packet
, sizeof(packet
));
444 if (write(d
->fd
, buf
, length
) < length
) {
445 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_voice_send() write() failed\n");
448 gg_dcc_debug_data("write", d
->fd
, buf
, length
);
453 #define gg_read(fd, buf, size) \
455 int tmp = read(fd, buf, size); \
457 if (tmp < (int) size) { \
459 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed (errno=%d, %s)\n", errno, strerror(errno)); \
460 } else if (tmp == 0) { \
461 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed, connection broken\n"); \
463 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed (%d bytes, %d needed)\n", tmp, size); \
465 e->type = GG_EVENT_DCC_ERROR; \
466 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; \
469 gg_dcc_debug_data("read", fd, buf, size); \
472 #define gg_write(fd, buf, size) \
475 gg_dcc_debug_data("write", fd, buf, size); \
476 tmp = write(fd, buf, size); \
477 if (tmp < (int) size) { \
479 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() write() failed (errno=%d, %s)\n", errno, strerror(errno)); \
481 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() write() failed (%d needed, %d done)\n", size, tmp); \
483 e->type = GG_EVENT_DCC_ERROR; \
484 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; \
492 * funkcja, któr± nale¿y wywo³aæ, gdy co¶ siê zmieni na gg_dcc->fd.
494 * - h - struktura zwrócona przez gg_create_dcc_socket()
496 * zaalokowana struct gg_event lub NULL, je¶li zabrak³o pamiêci na ni±.
498 struct gg_event
*gg_dcc_watch_fd(struct gg_dcc
*h
)
503 gg_debug(GG_DEBUG_FUNCTION
, "** gg_dcc_watch_fd(%p);\n", h
);
505 if (!h
|| (h
->type
!= GG_SESSION_DCC
&& h
->type
!= GG_SESSION_DCC_SOCKET
&& h
->type
!= GG_SESSION_DCC_SEND
&& h
->type
!= GG_SESSION_DCC_GET
&& h
->type
!= GG_SESSION_DCC_VOICE
)) {
506 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() invalid argument\n");
511 if (!(e
= (void*) calloc(1, sizeof(*e
)))) {
512 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() not enough memory\n");
516 e
->type
= GG_EVENT_NONE
;
518 if (h
->type
== GG_SESSION_DCC_SOCKET
) {
519 struct sockaddr_in sin
;
521 int fd
, sin_len
= sizeof(sin
), one
= 1;
523 if ((fd
= accept(h
->fd
, (struct sockaddr
*) &sin
, &sin_len
)) == -1) {
524 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() can't accept() new connection (errno=%d, %s)\n", errno
, strerror(errno
));
528 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() new direct connection from %s:%d\n", inet_ntoa(sin
.sin_addr
), htons(sin
.sin_port
));
531 if (ioctl(fd
, FIONBIO
, &one
) == -1) {
533 if (fcntl(fd
, F_SETFL
, O_NONBLOCK
) == -1) {
535 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() can't set nonblocking (errno=%d, %s)\n", errno
, strerror(errno
));
537 e
->type
= GG_EVENT_DCC_ERROR
;
538 e
->event
.dcc_error
= GG_ERROR_DCC_HANDSHAKE
;
542 if (!(c
= (void*) calloc(1, sizeof(*c
)))) {
543 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() not enough memory for client data\n");
551 c
->check
= GG_CHECK_READ
;
552 c
->state
= GG_STATE_READING_UIN_1
;
553 c
->type
= GG_SESSION_DCC
;
554 c
->timeout
= GG_DEFAULT_TIMEOUT
;
556 c
->remote_addr
= sin
.sin_addr
.s_addr
;
557 c
->remote_port
= ntohs(sin
.sin_port
);
559 e
->type
= GG_EVENT_DCC_NEW
;
560 e
->event
.dcc_new
= c
;
564 struct gg_dcc_tiny_packet tiny
;
565 struct gg_dcc_small_packet small
;
566 struct gg_dcc_big_packet big
;
567 int size
, tmp
, res
, res_size
= sizeof(res
);
569 char buf
[1024], ack
[] = "UDAG";
571 struct gg_dcc_file_info_packet
{
572 struct gg_dcc_big_packet big
;
573 struct gg_file_info file_info
;
575 struct gg_dcc_file_info_packet file_info_packet
;
578 case GG_STATE_READING_UIN_1
:
579 case GG_STATE_READING_UIN_2
:
583 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_READING_UIN_%d\n", (h
->state
== GG_STATE_READING_UIN_1
) ? 1 : 2);
585 gg_read(h
->fd
, &uin
, sizeof(uin
));
587 if (h
->state
== GG_STATE_READING_UIN_1
) {
588 h
->state
= GG_STATE_READING_UIN_2
;
589 h
->check
= GG_CHECK_READ
;
590 h
->timeout
= GG_DEFAULT_TIMEOUT
;
591 h
->peer_uin
= gg_fix32(uin
);
593 h
->state
= GG_STATE_SENDING_ACK
;
594 h
->check
= GG_CHECK_WRITE
;
595 h
->timeout
= GG_DEFAULT_TIMEOUT
;
596 h
->uin
= gg_fix32(uin
);
597 e
->type
= GG_EVENT_DCC_CLIENT_ACCEPT
;
603 case GG_STATE_SENDING_ACK
:
604 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_SENDING_ACK\n");
606 gg_write(h
->fd
, ack
, 4);
608 h
->state
= GG_STATE_READING_TYPE
;
609 h
->check
= GG_CHECK_READ
;
610 h
->timeout
= GG_DEFAULT_TIMEOUT
;
614 case GG_STATE_READING_TYPE
:
615 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_READING_TYPE\n");
617 gg_read(h
->fd
, &small
, sizeof(small
));
619 small
.type
= gg_fix32(small
.type
);
621 switch (small
.type
) {
622 case 0x0003: /* XXX */
623 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() callback\n");
624 h
->type
= GG_SESSION_DCC_SEND
;
625 h
->state
= GG_STATE_SENDING_FILE_INFO
;
626 h
->check
= GG_CHECK_WRITE
;
627 h
->timeout
= GG_DEFAULT_TIMEOUT
;
629 e
->type
= GG_EVENT_DCC_CALLBACK
;
633 case 0x0002: /* XXX */
634 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() dialin\n");
635 h
->type
= GG_SESSION_DCC_GET
;
636 h
->state
= GG_STATE_READING_REQUEST
;
637 h
->check
= GG_CHECK_READ
;
638 h
->timeout
= GG_DEFAULT_TIMEOUT
;
644 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() unknown dcc type (%.4x) from %ld\n", small
.type
, h
->peer_uin
);
645 e
->type
= GG_EVENT_DCC_ERROR
;
646 e
->event
.dcc_error
= GG_ERROR_DCC_HANDSHAKE
;
651 case GG_STATE_READING_REQUEST
:
652 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_READING_REQUEST\n");
654 gg_read(h
->fd
, &small
, sizeof(small
));
656 small
.type
= gg_fix32(small
.type
);
658 switch (small
.type
) {
659 case 0x0001: /* XXX */
660 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() file transfer request\n");
661 h
->state
= GG_STATE_READING_FILE_INFO
;
662 h
->check
= GG_CHECK_READ
;
663 h
->timeout
= GG_DEFAULT_TIMEOUT
;
666 case 0x0003: /* XXX */
667 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() voice chat request\n");
668 h
->state
= GG_STATE_SENDING_VOICE_ACK
;
669 h
->check
= GG_CHECK_WRITE
;
670 h
->timeout
= GG_DCC_TIMEOUT_VOICE_ACK
;
671 h
->type
= GG_SESSION_DCC_VOICE
;
672 e
->type
= GG_EVENT_DCC_NEED_VOICE_ACK
;
677 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() unknown dcc request (%.4x) from %ld\n", small
.type
, h
->peer_uin
);
678 e
->type
= GG_EVENT_DCC_ERROR
;
679 e
->event
.dcc_error
= GG_ERROR_DCC_HANDSHAKE
;
684 case GG_STATE_READING_FILE_INFO
:
685 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_INFO\n");
687 gg_read(h
->fd
, &file_info_packet
, sizeof(file_info_packet
));
689 memcpy(&h
->file_info
, &file_info_packet
.file_info
, sizeof(h
->file_info
));
691 h
->file_info
.mode
= gg_fix32(h
->file_info
.mode
);
692 h
->file_info
.size
= gg_fix32(h
->file_info
.size
);
694 h
->state
= GG_STATE_SENDING_FILE_ACK
;
695 h
->check
= GG_CHECK_WRITE
;
696 h
->timeout
= GG_DCC_TIMEOUT_FILE_ACK
;
698 e
->type
= GG_EVENT_DCC_NEED_FILE_ACK
;
702 case GG_STATE_SENDING_FILE_ACK
:
703 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_ACK\n");
705 big
.type
= gg_fix32(0x0006); /* XXX */
706 big
.dunno1
= gg_fix32(h
->offset
);
709 gg_write(h
->fd
, &big
, sizeof(big
));
711 h
->state
= GG_STATE_READING_FILE_HEADER
;
712 h
->chunk_size
= sizeof(big
);
714 if (!(h
->chunk_buf
= malloc(sizeof(big
)))) {
715 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() out of memory\n");
719 h
->check
= GG_CHECK_READ
;
720 h
->timeout
= GG_DEFAULT_TIMEOUT
;
724 case GG_STATE_SENDING_VOICE_ACK
:
725 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_SENDING_VOICE_ACK\n");
727 tiny
.type
= 0x01; /* XXX */
729 gg_write(h
->fd
, &tiny
, sizeof(tiny
));
731 h
->state
= GG_STATE_READING_VOICE_HEADER
;
732 h
->check
= GG_CHECK_READ
;
733 h
->timeout
= GG_DEFAULT_TIMEOUT
;
739 case GG_STATE_READING_FILE_HEADER
:
740 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_HEADER\n");
742 tmp
= read(h
->fd
, h
->chunk_buf
+ h
->chunk_offset
, h
->chunk_size
- h
->chunk_offset
);
745 gg_debug(GG_DEBUG_MISC
, "// gg_watch_fd() read() failed (errno=%d, %s)\n", errno
, strerror(errno
));
746 e
->type
= GG_EVENT_DCC_ERROR
;
747 e
->event
.dcc_error
= GG_ERROR_DCC_NET
;
751 gg_dcc_debug_data("read", h
->fd
, h
->chunk_buf
+ h
->chunk_offset
, h
->chunk_size
- h
->chunk_offset
);
753 h
->chunk_offset
+= tmp
;
755 if (h
->chunk_offset
< h
->chunk_size
)
758 memcpy(&big
, h
->chunk_buf
, sizeof(big
));
762 big
.type
= gg_fix32(big
.type
);
763 h
->chunk_size
= gg_fix32(big
.dunno1
);
766 if (big
.type
== 0x0005) { /* XXX */
767 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() transfer refused\n");
768 e
->type
= GG_EVENT_DCC_ERROR
;
769 e
->event
.dcc_error
= GG_ERROR_DCC_REFUSED
;
773 if (h
->chunk_size
== 0) {
774 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() empty chunk, EOF\n");
775 e
->type
= GG_EVENT_DCC_DONE
;
779 h
->state
= GG_STATE_GETTING_FILE
;
780 h
->check
= GG_CHECK_READ
;
781 h
->timeout
= GG_DEFAULT_TIMEOUT
;
786 case GG_STATE_READING_VOICE_HEADER
:
787 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_HEADER\n");
789 gg_read(h
->fd
, &tiny
, sizeof(tiny
));
793 h
->state
= GG_STATE_READING_VOICE_SIZE
;
794 h
->check
= GG_CHECK_READ
;
795 h
->timeout
= GG_DEFAULT_TIMEOUT
;
799 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() peer breaking connection\n");
800 /* XXX zwracaæ odpowiedni event */
802 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() unknown request (%.2x)\n", tiny
.type
);
803 e
->type
= GG_EVENT_DCC_ERROR
;
804 e
->event
.dcc_error
= GG_ERROR_DCC_HANDSHAKE
;
809 case GG_STATE_READING_VOICE_SIZE
:
810 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_SIZE\n");
812 gg_read(h
->fd
, &small
, sizeof(small
));
814 small
.type
= gg_fix32(small
.type
);
816 if (small
.type
< 16 || small
.type
> sizeof(buf
)) {
817 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() invalid voice frame size (%d)\n", small
.type
);
818 e
->type
= GG_EVENT_DCC_ERROR
;
819 e
->event
.dcc_error
= GG_ERROR_DCC_NET
;
824 h
->chunk_size
= small
.type
;
827 if (!(h
->voice_buf
= malloc(h
->chunk_size
))) {
828 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() out of memory for voice frame\n");
832 h
->state
= GG_STATE_READING_VOICE_DATA
;
833 h
->check
= GG_CHECK_READ
;
834 h
->timeout
= GG_DEFAULT_TIMEOUT
;
838 case GG_STATE_READING_VOICE_DATA
:
839 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_DATA\n");
841 tmp
= read(h
->fd
, h
->voice_buf
+ h
->chunk_offset
, h
->chunk_size
- h
->chunk_offset
);
844 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() read() failed (errno=%d, %s)\n", errno
, strerror(errno
));
846 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() read() failed, connection broken\n");
848 e
->type
= GG_EVENT_DCC_ERROR
;
849 e
->event
.dcc_error
= GG_ERROR_DCC_NET
;
853 gg_dcc_debug_data("read", h
->fd
, h
->voice_buf
+ h
->chunk_offset
, tmp
);
855 h
->chunk_offset
+= tmp
;
857 if (h
->chunk_offset
>= h
->chunk_size
) {
858 e
->type
= GG_EVENT_DCC_VOICE_DATA
;
859 e
->event
.dcc_voice_data
.data
= h
->voice_buf
;
860 e
->event
.dcc_voice_data
.length
= h
->chunk_size
;
861 h
->state
= GG_STATE_READING_VOICE_HEADER
;
866 h
->check
= GG_CHECK_READ
;
867 h
->timeout
= GG_DEFAULT_TIMEOUT
;
871 case GG_STATE_CONNECTING
:
875 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_CONNECTING\n");
878 if ((foo
= getsockopt(h
->fd
, SOL_SOCKET
, SO_ERROR
, &res
, &res_size
)) || res
) {
879 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() connection failed (fd=%d,errno=%d(%s),foo=%d,res=%d(%s))\n", h
->fd
, errno
, strerror(errno
), foo
, res
, strerror(res
));
880 e
->type
= GG_EVENT_DCC_ERROR
;
881 e
->event
.dcc_error
= GG_ERROR_DCC_HANDSHAKE
;
885 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() connected, sending uins\n");
887 uins
[0] = gg_fix32(h
->uin
);
888 uins
[1] = gg_fix32(h
->peer_uin
);
890 gg_write(h
->fd
, uins
, sizeof(uins
));
892 h
->state
= GG_STATE_READING_ACK
;
893 h
->check
= GG_CHECK_READ
;
894 h
->timeout
= GG_DEFAULT_TIMEOUT
;
899 case GG_STATE_READING_ACK
:
900 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_READING_ACK\n");
902 gg_read(h
->fd
, buf
, 4);
904 if (strncmp(buf
, ack
, 4)) {
905 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() did't get ack\n");
907 e
->type
= GG_EVENT_DCC_ERROR
;
908 e
->event
.dcc_error
= GG_ERROR_DCC_HANDSHAKE
;
912 h
->check
= GG_CHECK_WRITE
;
913 h
->timeout
= GG_DEFAULT_TIMEOUT
;
914 h
->state
= GG_STATE_SENDING_REQUEST
;
918 case GG_STATE_SENDING_VOICE_REQUEST
:
919 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_SENDING_VOICE_REQUEST\n");
921 small
.type
= gg_fix32(0x0003);
923 gg_write(h
->fd
, &small
, sizeof(small
));
925 h
->state
= GG_STATE_READING_VOICE_ACK
;
926 h
->check
= GG_CHECK_READ
;
927 h
->timeout
= GG_DEFAULT_TIMEOUT
;
931 case GG_STATE_SENDING_REQUEST
:
932 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_SENDING_REQUEST\n");
934 small
.type
= (h
->type
== GG_SESSION_DCC_GET
) ? gg_fix32(0x0003) : gg_fix32(0x0002); /* XXX */
936 gg_write(h
->fd
, &small
, sizeof(small
));
939 case GG_SESSION_DCC_GET
:
940 h
->state
= GG_STATE_READING_REQUEST
;
941 h
->check
= GG_CHECK_READ
;
942 h
->timeout
= GG_DEFAULT_TIMEOUT
;
945 case GG_SESSION_DCC_SEND
:
946 h
->state
= GG_STATE_SENDING_FILE_INFO
;
947 h
->check
= GG_CHECK_WRITE
;
948 h
->timeout
= GG_DEFAULT_TIMEOUT
;
950 if (h
->file_fd
== -1)
951 e
->type
= GG_EVENT_DCC_NEED_FILE_INFO
;
954 case GG_SESSION_DCC_VOICE
:
955 h
->state
= GG_STATE_SENDING_VOICE_REQUEST
;
956 h
->check
= GG_CHECK_WRITE
;
957 h
->timeout
= GG_DEFAULT_TIMEOUT
;
963 case GG_STATE_SENDING_FILE_INFO
:
964 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_INFO\n");
966 if (h
->file_fd
== -1) {
967 e
->type
= GG_EVENT_DCC_NEED_FILE_INFO
;
971 small
.type
= gg_fix32(0x0001); /* XXX */
973 gg_write(h
->fd
, &small
, sizeof(small
));
975 file_info_packet
.big
.type
= gg_fix32(0x0003); /* XXX */
976 file_info_packet
.big
.dunno1
= 0;
977 file_info_packet
.big
.dunno2
= 0;
979 memcpy(&file_info_packet
.file_info
, &h
->file_info
, sizeof(h
->file_info
));
981 /* zostaj± teraz u nas, wiêc odwracamy z powrotem */
982 h
->file_info
.size
= gg_fix32(h
->file_info
.size
);
983 h
->file_info
.mode
= gg_fix32(h
->file_info
.mode
);
985 gg_write(h
->fd
, &file_info_packet
, sizeof(file_info_packet
));
987 h
->state
= GG_STATE_READING_FILE_ACK
;
988 h
->check
= GG_CHECK_READ
;
989 h
->timeout
= GG_DCC_TIMEOUT_FILE_ACK
;
993 case GG_STATE_READING_FILE_ACK
:
994 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_ACK\n");
996 gg_read(h
->fd
, &big
, sizeof(big
));
998 /* XXX sprawdzaæ wynik */
999 h
->offset
= gg_fix32(big
.dunno1
);
1001 h
->state
= GG_STATE_SENDING_FILE_HEADER
;
1002 h
->check
= GG_CHECK_WRITE
;
1003 h
->timeout
= GG_DEFAULT_TIMEOUT
;
1005 e
->type
= GG_EVENT_DCC_ACK
;
1009 case GG_STATE_READING_VOICE_ACK
:
1010 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_ACK\n");
1012 gg_read(h
->fd
, &tiny
, sizeof(tiny
));
1014 if (tiny
.type
!= 0x01) {
1015 gg_debug(GG_DEBUG_MISC
, "// invalid reply (%.2x), connection refused\n", tiny
.type
);
1016 e
->type
= GG_EVENT_DCC_ERROR
;
1017 e
->event
.dcc_error
= GG_ERROR_DCC_REFUSED
;
1021 h
->state
= GG_STATE_READING_VOICE_HEADER
;
1022 h
->check
= GG_CHECK_READ
;
1023 h
->timeout
= GG_DEFAULT_TIMEOUT
;
1025 e
->type
= GG_EVENT_DCC_ACK
;
1029 case GG_STATE_SENDING_FILE_HEADER
:
1030 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_HEADER\n");
1032 h
->chunk_offset
= 0;
1034 if ((h
->chunk_size
= h
->file_info
.size
- h
->offset
) > 4096) {
1035 h
->chunk_size
= 4096;
1036 big
.type
= gg_fix32(0x0003); /* XXX */
1038 big
.type
= gg_fix32(0x0002); /* XXX */
1040 big
.dunno1
= gg_fix32(h
->chunk_size
);
1043 gg_write(h
->fd
, &big
, sizeof(big
));
1045 h
->state
= GG_STATE_SENDING_FILE
;
1046 h
->check
= GG_CHECK_WRITE
;
1047 h
->timeout
= GG_DEFAULT_TIMEOUT
;
1052 case GG_STATE_SENDING_FILE
:
1053 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE\n");
1055 if ((utmp
= h
->chunk_size
- h
->chunk_offset
) > sizeof(buf
))
1058 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() offset=%d, size=%d\n", h
->offset
, h
->file_info
.size
);
1059 lseek(h
->file_fd
, h
->offset
, SEEK_SET
);
1061 size
= read(h
->file_fd
, buf
, utmp
);
1065 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() read() failed. (errno=%d, %s)\n", errno
, strerror(errno
));
1067 e
->type
= GG_EVENT_DCC_ERROR
;
1068 e
->event
.dcc_error
= GG_ERROR_DCC_FILE
;
1075 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() read() reached eof\n");
1076 e
->type
= GG_EVENT_DCC_ERROR
;
1077 e
->event
.dcc_error
= GG_ERROR_DCC_EOF
;
1082 /* je¶li wczytali¶my wiêcej, utnijmy. */
1083 if (h
->offset
+ size
> h
->file_info
.size
) {
1084 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() read() too much (read=%d, ofs=%d, size=%d)\n", size
, h
->offset
, h
->file_info
.size
);
1085 size
= h
->file_info
.size
- h
->offset
;
1088 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() reached EOF after cutting\n");
1089 e
->type
= GG_EVENT_DCC_DONE
;
1094 tmp
= write(h
->fd
, buf
, size
);
1097 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() write() failed (%s)\n", strerror(errno
));
1098 e
->type
= GG_EVENT_DCC_ERROR
;
1099 e
->event
.dcc_error
= GG_ERROR_DCC_NET
;
1105 if (h
->offset
>= h
->file_info
.size
) {
1106 e
->type
= GG_EVENT_DCC_DONE
;
1110 h
->chunk_offset
+= size
;
1112 if (h
->chunk_offset
>= h
->chunk_size
) {
1113 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() chunk finished\n");
1114 h
->state
= GG_STATE_SENDING_FILE_HEADER
;
1115 h
->timeout
= GG_DEFAULT_TIMEOUT
;
1117 h
->state
= GG_STATE_SENDING_FILE
;
1118 h
->timeout
= GG_DCC_TIMEOUT_SEND
;
1121 h
->check
= GG_CHECK_WRITE
;
1125 case GG_STATE_GETTING_FILE
:
1126 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_GETTING_FILE\n");
1128 if ((utmp
= h
->chunk_size
- h
->chunk_offset
) > sizeof(buf
))
1131 size
= read(h
->fd
, buf
, utmp
);
1133 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() ofs=%d, size=%d, read()=%d\n", h
->offset
, h
->file_info
.size
, size
);
1137 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() read() failed. (errno=%d, %s)\n", errno
, strerror(errno
));
1139 e
->type
= GG_EVENT_DCC_ERROR
;
1140 e
->event
.dcc_error
= GG_ERROR_DCC_NET
;
1147 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() read() reached eof\n");
1148 e
->type
= GG_EVENT_DCC_ERROR
;
1149 e
->event
.dcc_error
= GG_ERROR_DCC_EOF
;
1154 tmp
= write(h
->file_fd
, buf
, size
);
1156 if (tmp
== -1 || tmp
< size
) {
1157 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() write() failed (%d:fd=%d:res=%d:%s)\n", tmp
, h
->file_fd
, size
, strerror(errno
));
1158 e
->type
= GG_EVENT_DCC_ERROR
;
1159 e
->event
.dcc_error
= GG_ERROR_DCC_NET
;
1165 if (h
->offset
>= h
->file_info
.size
) {
1166 e
->type
= GG_EVENT_DCC_DONE
;
1170 h
->chunk_offset
+= size
;
1172 if (h
->chunk_offset
>= h
->chunk_size
) {
1173 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() chunk finished\n");
1174 h
->state
= GG_STATE_READING_FILE_HEADER
;
1175 h
->timeout
= GG_DEFAULT_TIMEOUT
;
1176 h
->chunk_offset
= 0;
1177 h
->chunk_size
= sizeof(big
);
1178 if (!(h
->chunk_buf
= malloc(sizeof(big
)))) {
1179 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() out of memory\n");
1184 h
->state
= GG_STATE_GETTING_FILE
;
1185 h
->timeout
= GG_DCC_TIMEOUT_GET
;
1188 h
->check
= GG_CHECK_READ
;
1193 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_???\n");
1194 e
->type
= GG_EVENT_DCC_ERROR
;
1195 e
->event
.dcc_error
= GG_ERROR_DCC_HANDSHAKE
;
1210 * zwalnia pamiêæ po strukturze po³±czenia dcc.
1212 * - d - zwalniana struktura
1214 void gg_dcc_free(struct gg_dcc
*d
)
1216 gg_debug(GG_DEBUG_FUNCTION
, "** gg_dcc_free(%p);\n", d
);
1226 d
->chunk_buf
= NULL
;
1234 * c-indentation-style: k&r
1236 * indent-tabs-mode: notnil
1239 * vim: shiftwidth=8: