4 * (C) Copyright 2001-2006 Wojtek Kaniewski <wojtekka@irc.pl>
5 * Tomasz Chiliński <chilek@chilan.com>
6 * Adam Wysocki <gophi@ekg.apcoh.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License Version
10 * 2.1 as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
23 #include <sys/types.h>
25 #include <sys/ioctl.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
30 # include <sys/filio.h>
45 #ifndef GG_DEBUG_DISABLE
47 * gg_dcc_debug_data() // funkcja wewnętrzna
49 * wyświetla zrzut pakietu w hexie.
51 * - prefix - prefiks zrzutu pakietu
52 * - fd - deskryptor gniazda
53 * - buf - bufor z danymi
54 * - size - rozmiar danych
56 static void gg_dcc_debug_data(const char *prefix
, int fd
, const void *buf
, unsigned int size
)
60 gg_debug(GG_DEBUG_MISC
, "++ gg_dcc %s (fd=%d,len=%d)", prefix
, fd
, size
);
62 for (i
= 0; i
< size
; i
++)
63 gg_debug(GG_DEBUG_MISC
, " %.2x", ((unsigned char*) buf
)[i
]);
65 gg_debug(GG_DEBUG_MISC
, "\n");
68 #define gg_dcc_debug_data(a,b,c,d) do { } while (0)
74 * wysyła informację o tym, że dany klient powinien się z nami połączyć.
75 * wykorzystywane, kiedy druga strona, której chcemy coś wysłać jest za
78 * - sess - struktura opisująca sesję GG
79 * - uin - numerek odbiorcy
81 * patrz gg_send_message_ctcp().
83 int gg_dcc_request(struct gg_session
*sess
, uin_t uin
)
85 return gg_send_message_ctcp(sess
, GG_CLASS_CTCP
, uin
, "\002", 1);
89 * gg_dcc_fill_filetime() // funkcja wewnętrzna
91 * zamienia czas w postaci unixowej na windowsowy.
93 * - unix - czas w postaci unixowej
94 * - filetime - czas w postaci windowsowej
96 static void gg_dcc_fill_filetime(uint32_t ut
, uint32_t *ft
)
98 #ifdef __GG_LIBGADU_HAVE_LONG_LONG
99 unsigned long long tmp
;
102 tmp
+= 11644473600LL;
105 #ifndef __GG_LIBGADU_BIGENDIAN
106 ft
[0] = (uint32_t) tmp
;
107 ft
[1] = (uint32_t) (tmp
>> 32);
109 ft
[0] = gg_fix32((uint32_t) (tmp
>> 32));
110 ft
[1] = gg_fix32((uint32_t) tmp
);
117 * gg_dcc_fill_file_info()
119 * wypełnia pola struct gg_dcc niezbędne do wysłania pliku.
121 * - d - struktura opisująca połączenie DCC
122 * - filename - nazwa pliku
126 int gg_dcc_fill_file_info(struct gg_dcc
*d
, const char *filename
)
128 return gg_dcc_fill_file_info2(d
, filename
, filename
);
132 * gg_dcc_fill_file_info2()
134 * wypełnia pola struct gg_dcc niezbędne do wysłania pliku.
136 * - d - struktura opisująca połączenie DCC
137 * - filename - nazwa pliku
138 * - local_filename - nazwa na lokalnym systemie plików
142 int gg_dcc_fill_file_info2(struct gg_dcc
*d
, const char *filename
, const char *local_filename
)
145 const char *name
, *ext
, *p
;
149 gg_debug(GG_DEBUG_FUNCTION
, "** gg_dcc_fill_file_info2(%p, \"%s\", \"%s\");\n", d
, filename
, local_filename
);
151 if (!d
|| d
->type
!= GG_SESSION_DCC_SEND
) {
152 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_fill_file_info2() invalid arguments\n");
157 if (stat(local_filename
, &st
) == -1) {
158 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_fill_file_info2() stat() failed (%s)\n", strerror(errno
));
162 if ((st
.st_mode
& S_IFDIR
)) {
163 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_fill_file_info2() that's a directory\n");
168 if ((d
->file_fd
= open(local_filename
, O_RDONLY
)) == -1) {
169 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_fill_file_info2() open() failed (%s)\n", strerror(errno
));
173 memset(&d
->file_info
, 0, sizeof(d
->file_info
));
175 if (!(st
.st_mode
& S_IWUSR
))
176 d
->file_info
.mode
|= gg_fix32(GG_DCC_FILEATTR_READONLY
);
178 gg_dcc_fill_filetime(st
.st_atime
, d
->file_info
.atime
);
179 gg_dcc_fill_filetime(st
.st_mtime
, d
->file_info
.mtime
);
180 gg_dcc_fill_filetime(st
.st_ctime
, d
->file_info
.ctime
);
182 d
->file_info
.size
= gg_fix32(st
.st_size
);
183 d
->file_info
.mode
= gg_fix32(0x20); /* FILE_ATTRIBUTE_ARCHIVE */
185 if (!(name
= strrchr(filename
, '/')))
190 if (!(ext
= strrchr(name
, '.')))
191 ext
= name
+ strlen(name
);
193 for (i
= 0, p
= name
; i
< 8 && p
< ext
; i
++, p
++)
194 d
->file_info
.short_filename
[i
] = toupper(name
[i
]);
196 if (i
== 8 && p
< ext
) {
197 d
->file_info
.short_filename
[6] = '~';
198 d
->file_info
.short_filename
[7] = '1';
201 if (strlen(ext
) > 0) {
202 for (j
= 0; *ext
&& j
< 4; j
++, p
++)
203 d
->file_info
.short_filename
[i
+ j
] = toupper(ext
[j
]);
206 for (q
= d
->file_info
.short_filename
; *q
; q
++) {
209 } else if (*q
== 230) {
211 } else if (*q
== 234) {
213 } else if (*q
== 179) {
215 } else if (*q
== 241) {
217 } else if (*q
== 243) {
219 } else if (*q
== 156) {
221 } else if (*q
== 159) {
223 } else if (*q
== 191) {
228 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_fill_file_info2() short name \"%s\", dos name \"%s\"\n", name
, d
->file_info
.short_filename
);
229 strncpy(d
->file_info
.filename
, name
, sizeof(d
->file_info
.filename
) - 1);
235 * gg_dcc_transfer() // funkcja wewnętrzna
237 * inicjuje proces wymiany pliku z danym klientem.
239 * - ip - adres ip odbiorcy
240 * - port - port odbiorcy
241 * - my_uin - własny numer
242 * - peer_uin - numer obiorcy
243 * - type - rodzaj wymiany (GG_SESSION_DCC_SEND lub GG_SESSION_DCC_GET)
245 * zaalokowana struct gg_dcc lub NULL jeśli wystąpił błąd.
247 static struct gg_dcc
*gg_dcc_transfer(uint32_t ip
, uint16_t port
, uin_t my_uin
, uin_t peer_uin
, int type
)
249 struct gg_dcc
*d
= NULL
;
254 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");
256 if (!ip
|| ip
== INADDR_NONE
|| !port
|| !my_uin
|| !peer_uin
) {
257 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_transfer() invalid arguments\n");
262 if (!(d
= (void*) calloc(1, sizeof(*d
)))) {
263 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_transfer() not enough memory\n");
267 d
->check
= GG_CHECK_WRITE
;
268 d
->state
= GG_STATE_CONNECTING
;
270 d
->timeout
= GG_DEFAULT_TIMEOUT
;
275 d
->peer_uin
= peer_uin
;
277 if ((d
->fd
= gg_connect(&addr
, port
, 1)) == -1) {
278 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_transfer() connection failed\n");
289 * inicjuje proces odbierania pliku od danego klienta, gdy ten wysłał do
290 * nas żądanie połączenia.
292 * - ip - adres ip odbiorcy
293 * - port - port odbiorcy
294 * - my_uin - własny numer
295 * - peer_uin - numer obiorcy
297 * zaalokowana struct gg_dcc lub NULL jeśli wystąpił błąd.
299 struct gg_dcc
*gg_dcc_get_file(uint32_t ip
, uint16_t port
, uin_t my_uin
, uin_t peer_uin
)
301 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_get_file() handing over to gg_dcc_transfer()\n");
303 return gg_dcc_transfer(ip
, port
, my_uin
, peer_uin
, GG_SESSION_DCC_GET
);
309 * inicjuje proces wysyłania pliku do danego klienta.
311 * - ip - adres ip odbiorcy
312 * - port - port odbiorcy
313 * - my_uin - własny numer
314 * - peer_uin - numer obiorcy
316 * zaalokowana struct gg_dcc lub NULL jeśli wystąpił błąd.
318 struct gg_dcc
*gg_dcc_send_file(uint32_t ip
, uint16_t port
, uin_t my_uin
, uin_t peer_uin
)
320 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_send_file() handing over to gg_dcc_transfer()\n");
322 return gg_dcc_transfer(ip
, port
, my_uin
, peer_uin
, GG_SESSION_DCC_SEND
);
326 * gg_dcc_voice_chat()
328 * próbuje nawiązać połączenie głosowe.
330 * - ip - adres ip odbiorcy
331 * - port - port odbiorcy
332 * - my_uin - własny numer
333 * - peer_uin - numer obiorcy
335 * zaalokowana struct gg_dcc lub NULL jeśli wystąpił błąd.
337 struct gg_dcc
*gg_dcc_voice_chat(uint32_t ip
, uint16_t port
, uin_t my_uin
, uin_t peer_uin
)
339 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_voice_chat() handing over to gg_dcc_transfer()\n");
341 return gg_dcc_transfer(ip
, port
, my_uin
, peer_uin
, GG_SESSION_DCC_VOICE
);
347 * po zdarzeniu GG_EVENT_DCC_CALLBACK należy ustawić typ połączenia za
348 * pomocą tej funkcji.
350 * - d - struktura opisująca połączenie
351 * - type - typ połączenia (GG_SESSION_DCC_SEND lub GG_SESSION_DCC_VOICE)
353 void gg_dcc_set_type(struct gg_dcc
*d
, int type
)
356 d
->state
= (type
== GG_SESSION_DCC_SEND
) ? GG_STATE_SENDING_FILE_INFO
: GG_STATE_SENDING_VOICE_REQUEST
;
360 * gg_dcc_callback() // funkcja wewnętrzna
362 * wywoływana z struct gg_dcc->callback, odpala gg_dcc_watch_fd i umieszcza
363 * rezultat w struct gg_dcc->event.
365 * - d - structura opisująca połączenie
369 static int gg_dcc_callback(struct gg_dcc
*d
)
371 struct gg_event
*e
= gg_dcc_watch_fd(d
);
375 return (e
!= NULL
) ? 0 : -1;
379 * gg_dcc_socket_create()
381 * tworzy gniazdo dla bezpośredniej komunikacji między klientami.
383 * - uin - własny numer
384 * - port - preferowany port, jeśli równy 0 lub -1, próbuje domyślnego
386 * zaalokowana struct gg_dcc, którą poźniej należy zwolnić funkcją
387 * gg_dcc_free(), albo NULL jeśli wystąpił błąd.
389 struct gg_dcc
*gg_dcc_socket_create(uin_t uin
, uint16_t port
)
392 struct sockaddr_in sin
;
393 int sock
, bound
= 0, errno2
;
395 gg_debug(GG_DEBUG_FUNCTION
, "** gg_create_dcc_socket(%d, %d);\n", uin
, port
);
398 gg_debug(GG_DEBUG_MISC
, "// gg_create_dcc_socket() invalid arguments\n");
403 if ((sock
= socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
)) == -1) {
404 gg_debug(GG_DEBUG_MISC
, "// gg_create_dcc_socket() can't create socket (%s)\n", strerror(errno
));
409 port
= GG_DEFAULT_DCC_PORT
;
412 sin
.sin_family
= AF_INET
;
413 sin
.sin_addr
.s_addr
= INADDR_ANY
;
414 sin
.sin_port
= htons(port
);
416 gg_debug(GG_DEBUG_MISC
, "// gg_create_dcc_socket() trying port %d\n", port
);
417 if (!bind(sock
, (struct sockaddr
*) &sin
, sizeof(sin
)))
420 if (++port
== 65535) {
421 gg_debug(GG_DEBUG_MISC
, "// gg_create_dcc_socket() no free port found\n");
428 if (listen(sock
, 10)) {
429 gg_debug(GG_DEBUG_MISC
, "// gg_create_dcc_socket() unable to listen (%s)\n", strerror(errno
));
436 gg_debug(GG_DEBUG_MISC
, "// gg_create_dcc_socket() bound to port %d\n", port
);
438 if (!(c
= malloc(sizeof(*c
)))) {
439 gg_debug(GG_DEBUG_MISC
, "// gg_create_dcc_socket() not enough memory for struct\n");
443 memset(c
, 0, sizeof(*c
));
445 c
->port
= c
->id
= port
;
447 c
->type
= GG_SESSION_DCC_SOCKET
;
450 c
->state
= GG_STATE_LISTENING
;
451 c
->check
= GG_CHECK_READ
;
452 c
->callback
= gg_dcc_callback
;
453 c
->destroy
= gg_dcc_free
;
459 * gg_dcc_voice_send()
461 * wysyła ramkę danych dla rozmowy głosowej.
463 * - d - struktura opisująca połączenie dcc
464 * - buf - bufor z danymi
465 * - length - rozmiar ramki
469 int gg_dcc_voice_send(struct gg_dcc
*d
, char *buf
, int length
)
475 struct packet_s packet
;
477 gg_debug(GG_DEBUG_FUNCTION
, "++ gg_dcc_voice_send(%p, %p, %d);\n", d
, buf
, length
);
478 if (!d
|| !buf
|| length
< 0 || d
->type
!= GG_SESSION_DCC_VOICE
) {
479 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_voice_send() invalid argument\n");
484 packet
.type
= 0x03; /* XXX */
485 packet
.length
= gg_fix32(length
);
487 if (write(d
->fd
, &packet
, sizeof(packet
)) < (signed)sizeof(packet
)) {
488 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_voice_send() write() failed\n");
491 gg_dcc_debug_data("write", d
->fd
, &packet
, sizeof(packet
));
493 if (write(d
->fd
, buf
, length
) < length
) {
494 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_voice_send() write() failed\n");
497 gg_dcc_debug_data("write", d
->fd
, buf
, length
);
502 #define gg_read(fd, buf, size) \
504 int tmp = read(fd, buf, size); \
506 if (tmp < (int) size) { \
508 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed (errno=%d, %s)\n", errno, strerror(errno)); \
509 } else if (tmp == 0) { \
510 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed, connection broken\n"); \
512 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed (%d bytes, %d needed)\n", tmp, size); \
514 e->type = GG_EVENT_DCC_ERROR; \
515 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; \
518 gg_dcc_debug_data("read", fd, buf, size); \
521 #define gg_write(fd, buf, size) \
524 gg_dcc_debug_data("write", fd, buf, size); \
525 tmp = write(fd, buf, size); \
526 if (tmp < (int) size) { \
528 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() write() failed (errno=%d, %s)\n", errno, strerror(errno)); \
530 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() write() failed (%d needed, %d done)\n", size, tmp); \
532 e->type = GG_EVENT_DCC_ERROR; \
533 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; \
541 * funkcja, którą należy wywołać, gdy coś się zmieni na gg_dcc->fd.
543 * - h - struktura zwrócona przez gg_create_dcc_socket()
545 * zaalokowana struct gg_event lub NULL, jeśli zabrakło pamięci na nią.
547 struct gg_event
*gg_dcc_watch_fd(struct gg_dcc
*h
)
552 gg_debug(GG_DEBUG_FUNCTION
, "** gg_dcc_watch_fd(%p);\n", h
);
554 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
)) {
555 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() invalid argument\n");
560 if (!(e
= (void*) calloc(1, sizeof(*e
)))) {
561 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() not enough memory\n");
565 e
->type
= GG_EVENT_NONE
;
567 if (h
->type
== GG_SESSION_DCC_SOCKET
) {
568 struct sockaddr_in sin
;
570 int fd
, sin_len
= sizeof(sin
), one
= 1;
572 if ((fd
= accept(h
->fd
, (struct sockaddr
*) &sin
, &sin_len
)) == -1) {
573 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() can't accept() new connection (errno=%d, %s)\n", errno
, strerror(errno
));
577 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
));
580 if (ioctl(fd
, FIONBIO
, &one
) == -1) {
582 if (fcntl(fd
, F_SETFL
, O_NONBLOCK
) == -1) {
584 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() can't set nonblocking (errno=%d, %s)\n", errno
, strerror(errno
));
586 e
->type
= GG_EVENT_DCC_ERROR
;
587 e
->event
.dcc_error
= GG_ERROR_DCC_HANDSHAKE
;
591 if (!(c
= (void*) calloc(1, sizeof(*c
)))) {
592 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() not enough memory for client data\n");
600 c
->check
= GG_CHECK_READ
;
601 c
->state
= GG_STATE_READING_UIN_1
;
602 c
->type
= GG_SESSION_DCC
;
603 c
->timeout
= GG_DEFAULT_TIMEOUT
;
605 c
->remote_addr
= sin
.sin_addr
.s_addr
;
606 c
->remote_port
= ntohs(sin
.sin_port
);
608 e
->type
= GG_EVENT_DCC_NEW
;
609 e
->event
.dcc_new
= c
;
613 struct gg_dcc_tiny_packet tiny
;
614 struct gg_dcc_small_packet small
;
615 struct gg_dcc_big_packet big
;
616 int size
, tmp
, res
, res_size
= sizeof(res
);
618 char buf
[1024], ack
[] = "UDAG";
620 struct gg_dcc_file_info_packet
{
621 struct gg_dcc_big_packet big
;
622 struct gg_file_info file_info
;
624 struct gg_dcc_file_info_packet file_info_packet
;
627 case GG_STATE_READING_UIN_1
:
628 case GG_STATE_READING_UIN_2
:
632 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_READING_UIN_%d\n", (h
->state
== GG_STATE_READING_UIN_1
) ? 1 : 2);
634 gg_read(h
->fd
, &uin
, sizeof(uin
));
636 if (h
->state
== GG_STATE_READING_UIN_1
) {
637 h
->state
= GG_STATE_READING_UIN_2
;
638 h
->check
= GG_CHECK_READ
;
639 h
->timeout
= GG_DEFAULT_TIMEOUT
;
640 h
->peer_uin
= gg_fix32(uin
);
642 h
->state
= GG_STATE_SENDING_ACK
;
643 h
->check
= GG_CHECK_WRITE
;
644 h
->timeout
= GG_DEFAULT_TIMEOUT
;
645 h
->uin
= gg_fix32(uin
);
646 e
->type
= GG_EVENT_DCC_CLIENT_ACCEPT
;
652 case GG_STATE_SENDING_ACK
:
653 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_SENDING_ACK\n");
655 gg_write(h
->fd
, ack
, 4);
657 h
->state
= GG_STATE_READING_TYPE
;
658 h
->check
= GG_CHECK_READ
;
659 h
->timeout
= GG_DEFAULT_TIMEOUT
;
663 case GG_STATE_READING_TYPE
:
664 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_READING_TYPE\n");
666 gg_read(h
->fd
, &small
, sizeof(small
));
668 small
.type
= gg_fix32(small
.type
);
670 switch (small
.type
) {
671 case 0x0003: /* XXX */
672 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() callback\n");
673 h
->type
= GG_SESSION_DCC_SEND
;
674 h
->state
= GG_STATE_SENDING_FILE_INFO
;
675 h
->check
= GG_CHECK_WRITE
;
676 h
->timeout
= GG_DEFAULT_TIMEOUT
;
678 e
->type
= GG_EVENT_DCC_CALLBACK
;
682 case 0x0002: /* XXX */
683 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() dialin\n");
684 h
->type
= GG_SESSION_DCC_GET
;
685 h
->state
= GG_STATE_READING_REQUEST
;
686 h
->check
= GG_CHECK_READ
;
687 h
->timeout
= GG_DEFAULT_TIMEOUT
;
693 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() unknown dcc type (%.4x) from %ld\n", small
.type
, h
->peer_uin
);
694 e
->type
= GG_EVENT_DCC_ERROR
;
695 e
->event
.dcc_error
= GG_ERROR_DCC_HANDSHAKE
;
700 case GG_STATE_READING_REQUEST
:
701 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_READING_REQUEST\n");
703 gg_read(h
->fd
, &small
, sizeof(small
));
705 small
.type
= gg_fix32(small
.type
);
707 switch (small
.type
) {
708 case 0x0001: /* XXX */
709 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() file transfer request\n");
710 h
->state
= GG_STATE_READING_FILE_INFO
;
711 h
->check
= GG_CHECK_READ
;
712 h
->timeout
= GG_DEFAULT_TIMEOUT
;
715 case 0x0003: /* XXX */
716 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() voice chat request\n");
717 h
->state
= GG_STATE_SENDING_VOICE_ACK
;
718 h
->check
= GG_CHECK_WRITE
;
719 h
->timeout
= GG_DCC_TIMEOUT_VOICE_ACK
;
720 h
->type
= GG_SESSION_DCC_VOICE
;
721 e
->type
= GG_EVENT_DCC_NEED_VOICE_ACK
;
726 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() unknown dcc request (%.4x) from %ld\n", small
.type
, h
->peer_uin
);
727 e
->type
= GG_EVENT_DCC_ERROR
;
728 e
->event
.dcc_error
= GG_ERROR_DCC_HANDSHAKE
;
733 case GG_STATE_READING_FILE_INFO
:
734 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_INFO\n");
736 gg_read(h
->fd
, &file_info_packet
, sizeof(file_info_packet
));
738 memcpy(&h
->file_info
, &file_info_packet
.file_info
, sizeof(h
->file_info
));
740 h
->file_info
.mode
= gg_fix32(h
->file_info
.mode
);
741 h
->file_info
.size
= gg_fix32(h
->file_info
.size
);
743 h
->state
= GG_STATE_SENDING_FILE_ACK
;
744 h
->check
= GG_CHECK_WRITE
;
745 h
->timeout
= GG_DCC_TIMEOUT_FILE_ACK
;
747 e
->type
= GG_EVENT_DCC_NEED_FILE_ACK
;
751 case GG_STATE_SENDING_FILE_ACK
:
752 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_ACK\n");
754 big
.type
= gg_fix32(0x0006); /* XXX */
755 big
.dunno1
= gg_fix32(h
->offset
);
758 gg_write(h
->fd
, &big
, sizeof(big
));
760 h
->state
= GG_STATE_READING_FILE_HEADER
;
761 h
->chunk_size
= sizeof(big
);
763 if (!(h
->chunk_buf
= malloc(sizeof(big
)))) {
764 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() out of memory\n");
768 h
->check
= GG_CHECK_READ
;
769 h
->timeout
= GG_DEFAULT_TIMEOUT
;
773 case GG_STATE_SENDING_VOICE_ACK
:
774 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_SENDING_VOICE_ACK\n");
776 tiny
.type
= 0x01; /* XXX */
778 gg_write(h
->fd
, &tiny
, sizeof(tiny
));
780 h
->state
= GG_STATE_READING_VOICE_HEADER
;
781 h
->check
= GG_CHECK_READ
;
782 h
->timeout
= GG_DEFAULT_TIMEOUT
;
788 case GG_STATE_READING_FILE_HEADER
:
789 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_HEADER\n");
791 tmp
= read(h
->fd
, h
->chunk_buf
+ h
->chunk_offset
, h
->chunk_size
- h
->chunk_offset
);
794 gg_debug(GG_DEBUG_MISC
, "// gg_watch_fd() read() failed (errno=%d, %s)\n", errno
, strerror(errno
));
795 e
->type
= GG_EVENT_DCC_ERROR
;
796 e
->event
.dcc_error
= GG_ERROR_DCC_NET
;
800 gg_dcc_debug_data("read", h
->fd
, h
->chunk_buf
+ h
->chunk_offset
, h
->chunk_size
- h
->chunk_offset
);
802 h
->chunk_offset
+= tmp
;
804 if (h
->chunk_offset
< h
->chunk_size
)
807 memcpy(&big
, h
->chunk_buf
, sizeof(big
));
811 big
.type
= gg_fix32(big
.type
);
812 h
->chunk_size
= gg_fix32(big
.dunno1
);
815 if (big
.type
== 0x0005) { /* XXX */
816 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() transfer refused\n");
817 e
->type
= GG_EVENT_DCC_ERROR
;
818 e
->event
.dcc_error
= GG_ERROR_DCC_REFUSED
;
822 if (h
->chunk_size
== 0) {
823 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() empty chunk, EOF\n");
824 e
->type
= GG_EVENT_DCC_DONE
;
828 h
->state
= GG_STATE_GETTING_FILE
;
829 h
->check
= GG_CHECK_READ
;
830 h
->timeout
= GG_DEFAULT_TIMEOUT
;
835 case GG_STATE_READING_VOICE_HEADER
:
836 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_HEADER\n");
838 gg_read(h
->fd
, &tiny
, sizeof(tiny
));
842 h
->state
= GG_STATE_READING_VOICE_SIZE
;
843 h
->check
= GG_CHECK_READ
;
844 h
->timeout
= GG_DEFAULT_TIMEOUT
;
848 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() peer breaking connection\n");
849 /* XXX zwracać odpowiedni event */
851 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() unknown request (%.2x)\n", tiny
.type
);
852 e
->type
= GG_EVENT_DCC_ERROR
;
853 e
->event
.dcc_error
= GG_ERROR_DCC_HANDSHAKE
;
858 case GG_STATE_READING_VOICE_SIZE
:
859 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_SIZE\n");
861 gg_read(h
->fd
, &small
, sizeof(small
));
863 small
.type
= gg_fix32(small
.type
);
865 if (small
.type
< 16 || small
.type
> sizeof(buf
)) {
866 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() invalid voice frame size (%d)\n", small
.type
);
867 e
->type
= GG_EVENT_DCC_ERROR
;
868 e
->event
.dcc_error
= GG_ERROR_DCC_NET
;
873 h
->chunk_size
= small
.type
;
876 if (!(h
->voice_buf
= malloc(h
->chunk_size
))) {
877 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() out of memory for voice frame\n");
882 h
->state
= GG_STATE_READING_VOICE_DATA
;
883 h
->check
= GG_CHECK_READ
;
884 h
->timeout
= GG_DEFAULT_TIMEOUT
;
888 case GG_STATE_READING_VOICE_DATA
:
889 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_DATA\n");
891 tmp
= read(h
->fd
, h
->voice_buf
+ h
->chunk_offset
, h
->chunk_size
- h
->chunk_offset
);
894 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() read() failed (errno=%d, %s)\n", errno
, strerror(errno
));
896 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() read() failed, connection broken\n");
898 e
->type
= GG_EVENT_DCC_ERROR
;
899 e
->event
.dcc_error
= GG_ERROR_DCC_NET
;
903 gg_dcc_debug_data("read", h
->fd
, h
->voice_buf
+ h
->chunk_offset
, tmp
);
905 h
->chunk_offset
+= tmp
;
907 if (h
->chunk_offset
>= h
->chunk_size
) {
908 e
->type
= GG_EVENT_DCC_VOICE_DATA
;
909 e
->event
.dcc_voice_data
.data
= h
->voice_buf
;
910 e
->event
.dcc_voice_data
.length
= h
->chunk_size
;
911 h
->state
= GG_STATE_READING_VOICE_HEADER
;
915 h
->check
= GG_CHECK_READ
;
916 h
->timeout
= GG_DEFAULT_TIMEOUT
;
920 case GG_STATE_CONNECTING
:
924 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_CONNECTING\n");
927 if ((foo
= getsockopt(h
->fd
, SOL_SOCKET
, SO_ERROR
, &res
, &res_size
)) || res
) {
928 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
));
929 e
->type
= GG_EVENT_DCC_ERROR
;
930 e
->event
.dcc_error
= GG_ERROR_DCC_HANDSHAKE
;
934 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() connected, sending uins\n");
936 uins
[0] = gg_fix32(h
->uin
);
937 uins
[1] = gg_fix32(h
->peer_uin
);
939 gg_write(h
->fd
, uins
, sizeof(uins
));
941 h
->state
= GG_STATE_READING_ACK
;
942 h
->check
= GG_CHECK_READ
;
943 h
->timeout
= GG_DEFAULT_TIMEOUT
;
948 case GG_STATE_READING_ACK
:
949 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_READING_ACK\n");
951 gg_read(h
->fd
, buf
, 4);
953 if (strncmp(buf
, ack
, 4)) {
954 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() did't get ack\n");
956 e
->type
= GG_EVENT_DCC_ERROR
;
957 e
->event
.dcc_error
= GG_ERROR_DCC_HANDSHAKE
;
961 h
->check
= GG_CHECK_WRITE
;
962 h
->timeout
= GG_DEFAULT_TIMEOUT
;
963 h
->state
= GG_STATE_SENDING_REQUEST
;
967 case GG_STATE_SENDING_VOICE_REQUEST
:
968 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_SENDING_VOICE_REQUEST\n");
970 small
.type
= gg_fix32(0x0003);
972 gg_write(h
->fd
, &small
, sizeof(small
));
974 h
->state
= GG_STATE_READING_VOICE_ACK
;
975 h
->check
= GG_CHECK_READ
;
976 h
->timeout
= GG_DEFAULT_TIMEOUT
;
980 case GG_STATE_SENDING_REQUEST
:
981 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_SENDING_REQUEST\n");
983 small
.type
= (h
->type
== GG_SESSION_DCC_GET
) ? gg_fix32(0x0003) : gg_fix32(0x0002); /* XXX */
985 gg_write(h
->fd
, &small
, sizeof(small
));
988 case GG_SESSION_DCC_GET
:
989 h
->state
= GG_STATE_READING_REQUEST
;
990 h
->check
= GG_CHECK_READ
;
991 h
->timeout
= GG_DEFAULT_TIMEOUT
;
994 case GG_SESSION_DCC_SEND
:
995 h
->state
= GG_STATE_SENDING_FILE_INFO
;
996 h
->check
= GG_CHECK_WRITE
;
997 h
->timeout
= GG_DEFAULT_TIMEOUT
;
999 if (h
->file_fd
== -1)
1000 e
->type
= GG_EVENT_DCC_NEED_FILE_INFO
;
1003 case GG_SESSION_DCC_VOICE
:
1004 h
->state
= GG_STATE_SENDING_VOICE_REQUEST
;
1005 h
->check
= GG_CHECK_WRITE
;
1006 h
->timeout
= GG_DEFAULT_TIMEOUT
;
1012 case GG_STATE_SENDING_FILE_INFO
:
1013 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_INFO\n");
1015 if (h
->file_fd
== -1) {
1016 e
->type
= GG_EVENT_DCC_NEED_FILE_INFO
;
1020 small
.type
= gg_fix32(0x0001); /* XXX */
1022 gg_write(h
->fd
, &small
, sizeof(small
));
1024 file_info_packet
.big
.type
= gg_fix32(0x0003); /* XXX */
1025 file_info_packet
.big
.dunno1
= 0;
1026 file_info_packet
.big
.dunno2
= 0;
1028 memcpy(&file_info_packet
.file_info
, &h
->file_info
, sizeof(h
->file_info
));
1030 /* zostają teraz u nas, więc odwracamy z powrotem */
1031 h
->file_info
.size
= gg_fix32(h
->file_info
.size
);
1032 h
->file_info
.mode
= gg_fix32(h
->file_info
.mode
);
1034 gg_write(h
->fd
, &file_info_packet
, sizeof(file_info_packet
));
1036 h
->state
= GG_STATE_READING_FILE_ACK
;
1037 h
->check
= GG_CHECK_READ
;
1038 h
->timeout
= GG_DCC_TIMEOUT_FILE_ACK
;
1042 case GG_STATE_READING_FILE_ACK
:
1043 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_ACK\n");
1045 gg_read(h
->fd
, &big
, sizeof(big
));
1047 /* XXX sprawdzać wynik */
1048 h
->offset
= gg_fix32(big
.dunno1
);
1050 h
->state
= GG_STATE_SENDING_FILE_HEADER
;
1051 h
->check
= GG_CHECK_WRITE
;
1052 h
->timeout
= GG_DEFAULT_TIMEOUT
;
1054 e
->type
= GG_EVENT_DCC_ACK
;
1058 case GG_STATE_READING_VOICE_ACK
:
1059 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_ACK\n");
1061 gg_read(h
->fd
, &tiny
, sizeof(tiny
));
1063 if (tiny
.type
!= 0x01) {
1064 gg_debug(GG_DEBUG_MISC
, "// invalid reply (%.2x), connection refused\n", tiny
.type
);
1065 e
->type
= GG_EVENT_DCC_ERROR
;
1066 e
->event
.dcc_error
= GG_ERROR_DCC_REFUSED
;
1070 h
->state
= GG_STATE_READING_VOICE_HEADER
;
1071 h
->check
= GG_CHECK_READ
;
1072 h
->timeout
= GG_DEFAULT_TIMEOUT
;
1074 e
->type
= GG_EVENT_DCC_ACK
;
1078 case GG_STATE_SENDING_FILE_HEADER
:
1079 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_HEADER\n");
1081 h
->chunk_offset
= 0;
1083 if ((h
->chunk_size
= h
->file_info
.size
- h
->offset
) > 4096) {
1084 h
->chunk_size
= 4096;
1085 big
.type
= gg_fix32(0x0003); /* XXX */
1087 big
.type
= gg_fix32(0x0002); /* XXX */
1089 big
.dunno1
= gg_fix32(h
->chunk_size
);
1092 gg_write(h
->fd
, &big
, sizeof(big
));
1094 h
->state
= GG_STATE_SENDING_FILE
;
1095 h
->check
= GG_CHECK_WRITE
;
1096 h
->timeout
= GG_DEFAULT_TIMEOUT
;
1101 case GG_STATE_SENDING_FILE
:
1102 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE\n");
1104 if ((utmp
= h
->chunk_size
- h
->chunk_offset
) > sizeof(buf
))
1107 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() offset=%d, size=%d\n", h
->offset
, h
->file_info
.size
);
1110 if (h
->file_info
.size
== 0) {
1111 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() read() reached eof on empty file\n");
1112 e
->type
= GG_EVENT_DCC_DONE
;
1117 lseek(h
->file_fd
, h
->offset
, SEEK_SET
);
1119 size
= read(h
->file_fd
, buf
, utmp
);
1123 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() read() failed. (errno=%d, %s)\n", errno
, strerror(errno
));
1125 e
->type
= GG_EVENT_DCC_ERROR
;
1126 e
->event
.dcc_error
= GG_ERROR_DCC_FILE
;
1133 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() read() reached eof\n");
1134 e
->type
= GG_EVENT_DCC_ERROR
;
1135 e
->event
.dcc_error
= GG_ERROR_DCC_EOF
;
1140 /* jeśli wczytaliśmy więcej, utnijmy. */
1141 if (h
->offset
+ size
> h
->file_info
.size
) {
1142 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
);
1143 size
= h
->file_info
.size
- h
->offset
;
1146 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() reached EOF after cutting\n");
1147 e
->type
= GG_EVENT_DCC_DONE
;
1152 tmp
= write(h
->fd
, buf
, size
);
1155 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() write() failed (%s)\n", strerror(errno
));
1156 e
->type
= GG_EVENT_DCC_ERROR
;
1157 e
->event
.dcc_error
= GG_ERROR_DCC_NET
;
1163 if (h
->offset
>= h
->file_info
.size
) {
1164 e
->type
= GG_EVENT_DCC_DONE
;
1168 h
->chunk_offset
+= size
;
1170 if (h
->chunk_offset
>= h
->chunk_size
) {
1171 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() chunk finished\n");
1172 h
->state
= GG_STATE_SENDING_FILE_HEADER
;
1173 h
->timeout
= GG_DEFAULT_TIMEOUT
;
1175 h
->state
= GG_STATE_SENDING_FILE
;
1176 h
->timeout
= GG_DCC_TIMEOUT_SEND
;
1179 h
->check
= GG_CHECK_WRITE
;
1183 case GG_STATE_GETTING_FILE
:
1184 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_GETTING_FILE\n");
1186 if ((utmp
= h
->chunk_size
- h
->chunk_offset
) > sizeof(buf
))
1189 size
= read(h
->fd
, buf
, utmp
);
1191 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() ofs=%d, size=%d, read()=%d\n", h
->offset
, h
->file_info
.size
, size
);
1195 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() read() failed. (errno=%d, %s)\n", errno
, strerror(errno
));
1197 e
->type
= GG_EVENT_DCC_ERROR
;
1198 e
->event
.dcc_error
= GG_ERROR_DCC_NET
;
1205 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() read() reached eof\n");
1206 e
->type
= GG_EVENT_DCC_ERROR
;
1207 e
->event
.dcc_error
= GG_ERROR_DCC_EOF
;
1212 tmp
= write(h
->file_fd
, buf
, size
);
1214 if (tmp
== -1 || tmp
< size
) {
1215 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
));
1216 e
->type
= GG_EVENT_DCC_ERROR
;
1217 e
->event
.dcc_error
= GG_ERROR_DCC_NET
;
1223 if (h
->offset
>= h
->file_info
.size
) {
1224 e
->type
= GG_EVENT_DCC_DONE
;
1228 h
->chunk_offset
+= size
;
1230 if (h
->chunk_offset
>= h
->chunk_size
) {
1231 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() chunk finished\n");
1232 h
->state
= GG_STATE_READING_FILE_HEADER
;
1233 h
->timeout
= GG_DEFAULT_TIMEOUT
;
1234 h
->chunk_offset
= 0;
1235 h
->chunk_size
= sizeof(big
);
1236 if (!(h
->chunk_buf
= malloc(sizeof(big
)))) {
1237 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() out of memory\n");
1242 h
->state
= GG_STATE_GETTING_FILE
;
1243 h
->timeout
= GG_DCC_TIMEOUT_GET
;
1246 h
->check
= GG_CHECK_READ
;
1251 gg_debug(GG_DEBUG_MISC
, "// gg_dcc_watch_fd() GG_STATE_???\n");
1252 e
->type
= GG_EVENT_DCC_ERROR
;
1253 e
->event
.dcc_error
= GG_ERROR_DCC_HANDSHAKE
;
1268 * zwalnia pamięć po strukturze połączenia dcc.
1270 * - d - zwalniana struktura
1272 void gg_dcc_free(struct gg_dcc
*d
)
1274 gg_debug(GG_DEBUG_FUNCTION
, "** gg_dcc_free(%p);\n", d
);
1284 d
->chunk_buf
= NULL
;
1292 * c-indentation-style: k&r
1294 * indent-tabs-mode: notnil
1297 * vim: shiftwidth=8: