Fixed bug #52
[centerim.git] / libgadu / dcc.c
blob15ef865b862bf6c5dcdeaba6a50e2960bb67c0c3
1 /* $Id: dcc.c,v 1.1 2004/01/26 23:49:33 konst Exp $ */
3 /*
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>
22 #include <sys/stat.h>
23 #include <sys/ioctl.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #ifdef sun
28 # include <sys/filio.h>
29 #endif
31 #include <ctype.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <stdarg.h>
35 #include <string.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <unistd.h>
40 #include "compat.h"
41 #include "libgadu.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)
56 unsigned int i;
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");
65 #else
66 #define gg_dcc_debug_data(a,b,c,d) do { } while (0)
67 #endif
70 * gg_dcc_request()
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
74 * maskarad±.
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);
86 /*
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;
99 tmp = ut;
100 tmp += 11644473600LL;
101 tmp *= 10000000LL;
103 #ifndef __GG_LIBGADU_BIGENDIAN
104 ft[0] = (uint32_t) tmp;
105 ft[1] = (uint32_t) (tmp >> 32);
106 #else
107 ft[0] = gg_fix32((uint32_t) (tmp >> 32));
108 ft[1] = gg_fix32((uint32_t) tmp);
109 #endif
111 #endif
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
122 * 0, -1.
124 int gg_dcc_fill_file_info(struct gg_dcc *d, const char *filename)
126 struct stat st;
127 const char *name, *ext, *p;
128 int i, j;
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");
134 errno = EINVAL;
135 return -1;
138 if (stat(filename, &st) == -1) {
139 gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info() stat() failed (%s)\n", strerror(errno));
140 return -1;
143 if ((st.st_mode & S_IFDIR)) {
144 gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info() that's a directory\n");
145 errno = EINVAL;
146 return -1;
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));
151 return -1;
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, '/')))
167 name = filename;
168 else
169 name++;
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);
186 return 0;
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;
205 struct in_addr addr;
207 addr.s_addr = ip;
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");
213 errno = EINVAL;
214 return NULL;
217 if (!(d = (void*) calloc(1, sizeof(*d)))) {
218 gg_debug(GG_DEBUG_MISC, "// gg_dcc_transfer() not enough memory\n");
219 return NULL;
222 d->check = GG_CHECK_WRITE;
223 d->state = GG_STATE_CONNECTING;
224 d->type = type;
225 d->timeout = GG_DEFAULT_TIMEOUT;
226 d->file_fd = -1;
227 d->active = 1;
228 d->fd = -1;
229 d->uin = my_uin;
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");
234 free(d);
235 return NULL;
238 return d;
242 * gg_dcc_get_file()
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);
262 * gg_dcc_send_file()
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);
300 * gg_dcc_set_type()
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)
310 d->type = 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
322 * 0, -1.
324 static int gg_dcc_callback(struct gg_dcc *d)
326 struct gg_event *e = gg_dcc_watch_fd(d);
328 d->event = e;
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)
346 struct gg_dcc *c;
347 struct sockaddr_in sin;
348 int sock, bound = 0;
350 gg_debug(GG_DEBUG_FUNCTION, "** gg_create_dcc_socket(%d, %d);\n", uin, port);
352 if (!uin) {
353 gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() invalid arguments\n");
354 errno = EINVAL;
355 return NULL;
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));
360 return NULL;
363 if (!port)
364 port = GG_DEFAULT_DCC_PORT;
366 while (!bound) {
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)))
373 bound = 1;
374 else {
375 if (++port == 65535) {
376 gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() no free port found\n");
377 return NULL;
382 if (listen(sock, 10)) {
383 gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() unable to listen (%s)\n", strerror(errno));
384 return NULL;
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");
391 close(sock);
392 return NULL;
394 memset(c, 0, sizeof(*c));
396 c->port = c->id = port;
397 c->fd = sock;
398 c->type = GG_SESSION_DCC_SOCKET;
399 c->uin = uin;
400 c->timeout = -1;
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;
407 return c;
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
419 * 0, -1.
421 int gg_dcc_voice_send(struct gg_dcc *d, char *buf, int length)
423 struct packet_s {
424 uint8_t type;
425 uint32_t length;
426 } GG_PACKED;
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");
432 return -1;
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");
440 return -1;
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");
446 return -1;
448 gg_dcc_debug_data("write", d->fd, buf, length);
450 return 0;
453 #define gg_read(fd, buf, size) \
455 int tmp = read(fd, buf, size); \
457 if (tmp < (int) size) { \
458 if (tmp == -1) { \
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"); \
462 } else { \
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; \
467 return e; \
469 gg_dcc_debug_data("read", fd, buf, size); \
472 #define gg_write(fd, buf, size) \
474 int tmp; \
475 gg_dcc_debug_data("write", fd, buf, size); \
476 tmp = write(fd, buf, size); \
477 if (tmp < (int) size) { \
478 if (tmp == -1) { \
479 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() write() failed (errno=%d, %s)\n", errno, strerror(errno)); \
480 } else { \
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; \
485 return e; \
490 * gg_dcc_watch_fd()
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)
500 struct gg_event *e;
501 int foo;
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");
507 errno = EINVAL;
508 return NULL;
511 if (!(e = (void*) calloc(1, sizeof(*e)))) {
512 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() not enough memory\n");
513 return NULL;
516 e->type = GG_EVENT_NONE;
518 if (h->type == GG_SESSION_DCC_SOCKET) {
519 struct sockaddr_in sin;
520 struct gg_dcc *c;
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));
525 return e;
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));
530 #ifdef FIONBIO
531 if (ioctl(fd, FIONBIO, &one) == -1) {
532 #else
533 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
534 #endif
535 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() can't set nonblocking (errno=%d, %s)\n", errno, strerror(errno));
536 close(fd);
537 e->type = GG_EVENT_DCC_ERROR;
538 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE;
539 return e;
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");
545 free(e);
546 close(fd);
547 return NULL;
550 c->fd = fd;
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;
555 c->file_fd = -1;
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;
562 return e;
563 } else {
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);
568 unsigned int utmp;
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;
574 } GG_PACKED;
575 struct gg_dcc_file_info_packet file_info_packet;
577 switch (h->state) {
578 case GG_STATE_READING_UIN_1:
579 case GG_STATE_READING_UIN_2:
581 uin_t uin;
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);
592 } else {
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;
600 return e;
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;
612 return e;
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;
631 break;
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;
639 h->incoming = 1;
641 break;
643 default:
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;
649 return e;
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;
664 break;
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;
674 break;
676 default:
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;
682 return e;
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;
700 return e;
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);
707 big.dunno2 = 0;
709 gg_write(h->fd, &big, sizeof(big));
711 h->state = GG_STATE_READING_FILE_HEADER;
712 h->chunk_size = sizeof(big);
713 h->chunk_offset = 0;
714 if (!(h->chunk_buf = malloc(sizeof(big)))) {
715 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() out of memory\n");
716 free(e);
717 return NULL;
719 h->check = GG_CHECK_READ;
720 h->timeout = GG_DEFAULT_TIMEOUT;
722 return e;
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;
735 h->offset = 0;
737 return e;
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);
744 if (tmp == -1) {
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;
748 return e;
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)
756 return e;
758 memcpy(&big, h->chunk_buf, sizeof(big));
759 free(h->chunk_buf);
760 h->chunk_buf = NULL;
762 big.type = gg_fix32(big.type);
763 h->chunk_size = gg_fix32(big.dunno1);
764 h->chunk_offset = 0;
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;
770 return e;
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;
776 return e;
779 h->state = GG_STATE_GETTING_FILE;
780 h->check = GG_CHECK_READ;
781 h->timeout = GG_DEFAULT_TIMEOUT;
782 h->established = 1;
784 return e;
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));
791 switch (tiny.type) {
792 case 0x03: /* XXX */
793 h->state = GG_STATE_READING_VOICE_SIZE;
794 h->check = GG_CHECK_READ;
795 h->timeout = GG_DEFAULT_TIMEOUT;
796 h->established = 1;
797 break;
798 case 0x04: /* XXX */
799 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() peer breaking connection\n");
800 /* XXX zwracaæ odpowiedni event */
801 default:
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;
807 return e;
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;
821 return e;
824 h->chunk_size = small.type;
825 h->chunk_offset = 0;
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");
829 return NULL;
832 h->state = GG_STATE_READING_VOICE_DATA;
833 h->check = GG_CHECK_READ;
834 h->timeout = GG_DEFAULT_TIMEOUT;
836 return e;
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);
842 if (tmp < 1) {
843 if (tmp == -1) {
844 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed (errno=%d, %s)\n", errno, strerror(errno));
845 } else {
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;
850 return e;
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;
862 h->voice_buf = NULL;
866 h->check = GG_CHECK_READ;
867 h->timeout = GG_DEFAULT_TIMEOUT;
869 return e;
871 case GG_STATE_CONNECTING:
873 uin_t uins[2];
875 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_CONNECTING\n");
877 res = 0;
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;
882 return e;
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;
896 return e;
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;
909 return e;
912 h->check = GG_CHECK_WRITE;
913 h->timeout = GG_DEFAULT_TIMEOUT;
914 h->state = GG_STATE_SENDING_REQUEST;
916 return e;
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;
929 return e;
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));
938 switch (h->type) {
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;
943 break;
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;
952 break;
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;
958 break;
961 return e;
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;
968 return e;
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;
991 return e;
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;
1007 return e;
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;
1018 return e;
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;
1027 return e;
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 */
1037 } else
1038 big.type = gg_fix32(0x0002); /* XXX */
1040 big.dunno1 = gg_fix32(h->chunk_size);
1041 big.dunno2 = 0;
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;
1048 h->established = 1;
1050 return e;
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))
1056 utmp = 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);
1063 /* b³±d */
1064 if (size == -1) {
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;
1070 return e;
1073 /* koniec pliku? */
1074 if (size == 0) {
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;
1079 return e;
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;
1087 if (size < 1) {
1088 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() reached EOF after cutting\n");
1089 e->type = GG_EVENT_DCC_DONE;
1090 return e;
1094 tmp = write(h->fd, buf, size);
1096 if (tmp == -1) {
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;
1100 return e;
1103 h->offset += size;
1105 if (h->offset >= h->file_info.size) {
1106 e->type = GG_EVENT_DCC_DONE;
1107 return e;
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;
1116 } else {
1117 h->state = GG_STATE_SENDING_FILE;
1118 h->timeout = GG_DCC_TIMEOUT_SEND;
1121 h->check = GG_CHECK_WRITE;
1123 return e;
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))
1129 utmp = 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);
1135 /* b³±d */
1136 if (size == -1) {
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;
1142 return e;
1145 /* koniec? */
1146 if (size == 0) {
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;
1151 return e;
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;
1160 return e;
1163 h->offset += size;
1165 if (h->offset >= h->file_info.size) {
1166 e->type = GG_EVENT_DCC_DONE;
1167 return e;
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");
1180 free(e);
1181 return NULL;
1183 } else {
1184 h->state = GG_STATE_GETTING_FILE;
1185 h->timeout = GG_DCC_TIMEOUT_GET;
1188 h->check = GG_CHECK_READ;
1190 return e;
1192 default:
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;
1197 return e;
1201 return e;
1204 #undef gg_read
1205 #undef gg_write
1208 * gg_dcc_free()
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);
1218 if (!d)
1219 return;
1221 if (d->fd != -1)
1222 close(d->fd);
1224 if (d->chunk_buf) {
1225 free(d->chunk_buf);
1226 d->chunk_buf = NULL;
1229 free(d);
1233 * Local variables:
1234 * c-indentation-style: k&r
1235 * c-basic-offset: 8
1236 * indent-tabs-mode: notnil
1237 * End:
1239 * vim: shiftwidth=8: