configure: fix execution with dash
[rofl0r-ixchat.git] / src / common / dcc.c
blobe96d26b7f33b55f32ef5567df8321b00abf18eb9
1 /* X-Chat
2 * Copyright (C) 1998-2006 Peter Zelezny.
3 * Copyright (C) 2006 Damjan Jovanovic
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 * Wayne Conrad, 3 Apr 1999: Color-coded DCC file transfer status windows
20 * Bernhard Valenti <bernhard.valenti@gmx.net> 2000-11-21: Fixed DCC send behind nat
22 * 2001-03-08 Added support for getting "dcc_ip" config parameter.
23 * Jim Seymour (jseymour@LinxNet.com)
26 /* we only use 32 bits, but without this define, you get only 31! */
27 #define _FILE_OFFSET_BITS 64
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
32 #include <errno.h>
33 #include <sys/stat.h>
34 #include <unistd.h>
35 #include <fcntl.h>
37 #define WANTSOCKET
38 #define WANTARPA
39 #define WANTDNS
40 #include "inet.h"
42 #include "xchat.h"
43 #include "util.h"
44 #include "fe.h"
45 #include "outbound.h"
46 #include "inbound.h"
47 #include "network.h"
48 #include "plugin.h"
49 #include "server.h"
50 #include "text.h"
51 #include "url.h"
52 #include "xchatc.h"
54 #ifdef USE_DCC64
55 #define BIG_STR_TO_INT(x) strtoull(x,NULL,10)
56 #else
57 #define BIG_STR_TO_INT(x) strtoul(x,NULL,10)
58 #endif
60 static char *dcctypes[] = { "SEND", "RECV", "CHAT", "CHAT" };
62 struct dccstat_info dccstat[] = {
63 {N_("Waiting"), 1 /*black */ },
64 {N_("Active"), 12 /*cyan */ },
65 {N_("Failed"), 4 /*red */ },
66 {N_("Done"), 3 /*green */ },
67 {N_("Connect"), 1 /*black */ },
68 {N_("Aborted"), 4 /*red */ },
71 static int dcc_global_throttle; /* 0x1 = sends, 0x2 = gets */
72 /*static*/ int dcc_sendcpssum, dcc_getcpssum;
74 static struct DCC *new_dcc (void);
75 static void dcc_close (struct DCC *dcc, int dccstat, int destroy);
76 static gboolean dcc_send_data (GIOChannel *, GIOCondition, struct DCC *);
77 static gboolean dcc_read (GIOChannel *, GIOCondition, struct DCC *);
78 static gboolean dcc_read_ack (GIOChannel *source, GIOCondition condition, struct DCC *dcc);
80 static int new_id()
82 static int id = 0;
83 if (id == 0)
85 /* start the first ID at a random number for pseudo security */
86 /* 1 - 255 */
87 id = RAND_INT(255) + 1;
88 /* ignore overflows, since it can go to 2 billion */
90 return id++;
93 static double
94 timeval_diff (GTimeVal *greater,
95 GTimeVal *less)
97 long usecdiff;
98 double result;
100 result = greater->tv_sec - less->tv_sec;
101 usecdiff = (long) greater->tv_usec - less->tv_usec;
102 result += (double) usecdiff / 1000000;
104 return result;
107 static void
108 dcc_unthrottle (struct DCC *dcc)
110 /* don't unthrottle here, but delegate to funcs */
111 if (dcc->type == TYPE_RECV)
112 dcc_read (NULL, 0, dcc);
113 else
114 dcc_send_data (NULL, 0, dcc);
117 static void
118 dcc_calc_cps (struct DCC *dcc)
120 GTimeVal now;
121 int oldcps;
122 double timediff, startdiff;
123 int glob_throttle_bit, wasthrottled;
124 int *cpssum, glob_limit;
125 DCC_SIZE pos, posdiff;
127 g_get_current_time (&now);
129 /* the pos we use for sends is an average
130 between pos and ack */
131 if (dcc->type == TYPE_SEND)
133 /* carefull to avoid 32bit overflow */
134 pos = dcc->pos - ((dcc->pos - dcc->ack) / 2);
135 glob_throttle_bit = 0x1;
136 cpssum = &dcc_sendcpssum;
137 glob_limit = prefs.dcc_global_max_send_cps;
139 else
141 pos = dcc->pos;
142 glob_throttle_bit = 0x2;
143 cpssum = &dcc_getcpssum;
144 glob_limit = prefs.dcc_global_max_get_cps;
147 if (!dcc->firstcpstv.tv_sec && !dcc->firstcpstv.tv_usec)
148 dcc->firstcpstv = now;
149 else
151 startdiff = timeval_diff (&now, &dcc->firstcpstv);
152 if (startdiff < 1)
153 startdiff = 1;
154 else if (startdiff > CPS_AVG_WINDOW)
155 startdiff = CPS_AVG_WINDOW;
157 timediff = timeval_diff (&now, &dcc->lastcpstv);
158 if (timediff > startdiff)
159 timediff = startdiff = 1;
161 posdiff = pos - dcc->lastcpspos;
162 oldcps = dcc->cps;
163 dcc->cps = ((double) posdiff / timediff) * (timediff / startdiff) +
164 (double) dcc->cps * (1.0 - (timediff / startdiff));
166 *cpssum += dcc->cps - oldcps;
169 dcc->lastcpspos = pos;
170 dcc->lastcpstv = now;
172 /* now check cps against set limits... */
173 wasthrottled = dcc->throttled;
175 /* check global limits first */
176 dcc->throttled &= ~0x2;
177 if (glob_limit > 0 && *cpssum >= glob_limit)
179 dcc_global_throttle |= glob_throttle_bit;
180 if (dcc->maxcps >= 0)
181 dcc->throttled |= 0x2;
183 else
184 dcc_global_throttle &= ~glob_throttle_bit;
186 /* now check per-connection limit */
187 if (dcc->maxcps > 0 && dcc->cps > dcc->maxcps)
188 dcc->throttled |= 0x1;
189 else
190 dcc->throttled &= ~0x1;
192 /* take action */
193 if (wasthrottled && !dcc->throttled)
194 dcc_unthrottle (dcc);
197 static void
198 dcc_remove_from_sum (struct DCC *dcc)
200 if (dcc->dccstat != STAT_ACTIVE)
201 return;
202 if (dcc->type == TYPE_SEND)
203 dcc_sendcpssum -= dcc->cps;
204 else if (dcc->type == TYPE_RECV)
205 dcc_getcpssum -= dcc->cps;
208 gboolean
209 is_dcc (struct DCC *dcc)
211 GSList *list = dcc_list;
212 while (list)
214 if (list->data == dcc)
215 return TRUE;
216 list = list->next;
218 return FALSE;
221 /* this is called from xchat.c:xchat_misc_checks() every 1 second. */
223 void
224 dcc_check_timeouts (void)
226 struct DCC *dcc;
227 time_t tim = time (0);
228 GSList *next, *list = dcc_list;
230 while (list)
232 dcc = (struct DCC *) list->data;
233 next = list->next;
235 switch (dcc->dccstat)
237 case STAT_ACTIVE:
238 dcc_calc_cps (dcc);
239 fe_dcc_update (dcc);
241 if (dcc->type == TYPE_SEND || dcc->type == TYPE_RECV)
243 if (prefs.dccstalltimeout > 0)
245 if (!dcc->throttled
246 && tim - dcc->lasttime > prefs.dccstalltimeout)
248 EMIT_SIGNAL (XP_TE_DCCSTALL, dcc->serv->front_session,
249 dcctypes[dcc->type],
250 file_part (dcc->file), dcc->nick, NULL, 0);
251 dcc_close (dcc, STAT_ABORTED, FALSE);
255 break;
256 case STAT_QUEUED:
257 if (dcc->type == TYPE_SEND || dcc->type == TYPE_CHATSEND)
259 if (tim - dcc->offertime > prefs.dcctimeout)
261 if (prefs.dcctimeout > 0)
263 EMIT_SIGNAL (XP_TE_DCCTOUT, dcc->serv->front_session,
264 dcctypes[dcc->type],
265 file_part (dcc->file), dcc->nick, NULL, 0);
266 dcc_close (dcc, STAT_ABORTED, FALSE);
270 break;
271 case STAT_DONE:
272 case STAT_FAILED:
273 case STAT_ABORTED:
274 if (prefs.dcc_remove)
275 dcc_close (dcc, 0, TRUE);
276 break;
278 list = next;
282 static int
283 dcc_lookup_proxy (char *host, struct sockaddr_in *addr)
285 struct hostent *h;
286 static char *cache_host = NULL;
287 static guint32 cache_addr;
289 /* too lazy to thread this, so we cache results */
290 if (cache_host)
292 if (strcmp (host, cache_host) == 0)
294 memcpy (&addr->sin_addr, &cache_addr, 4);
295 return TRUE;
297 free (cache_host);
298 cache_host = NULL;
301 h = gethostbyname (host);
302 if (h != NULL && h->h_length == 4 && h->h_addr_list[0] != NULL)
304 memcpy (&addr->sin_addr, h->h_addr, 4);
305 memcpy (&cache_addr, h->h_addr, 4);
306 cache_host = strdup (host);
307 return TRUE;
310 return FALSE;
313 #define DCC_USE_PROXY() (prefs.proxy_host[0] && prefs.proxy_type>0 && prefs.proxy_type<5 && prefs.proxy_use!=1)
315 static int
316 dcc_connect_sok (struct DCC *dcc)
318 int sok;
319 struct sockaddr_in addr;
321 sok = socket (AF_INET, SOCK_STREAM, 0);
322 if (sok == -1)
323 return -1;
325 memset (&addr, 0, sizeof (addr));
326 addr.sin_family = AF_INET;
327 if (DCC_USE_PROXY ())
329 if (!dcc_lookup_proxy (prefs.proxy_host, &addr))
331 closesocket (sok);
332 return -1;
334 addr.sin_port = htons (prefs.proxy_port);
336 else
338 addr.sin_port = htons (dcc->port);
339 addr.sin_addr.s_addr = htonl (dcc->addr);
342 set_nonblocking (sok);
343 connect (sok, (struct sockaddr *) &addr, sizeof (addr));
345 return sok;
348 static void
349 dcc_close (struct DCC *dcc, int dccstat, int destroy)
351 if (dcc->wiotag)
353 fe_input_remove (dcc->wiotag);
354 dcc->wiotag = 0;
357 if (dcc->iotag)
359 fe_input_remove (dcc->iotag);
360 dcc->iotag = 0;
363 if (dcc->sok != -1)
365 closesocket (dcc->sok);
366 dcc->sok = -1;
369 dcc_remove_from_sum (dcc);
371 if (dcc->fp != -1)
373 close (dcc->fp);
374 dcc->fp = -1;
376 if(dccstat == STAT_DONE)
378 /* if we just completed a dcc recieve, move the */
379 /* completed file to the completed directory */
380 if(dcc->type == TYPE_RECV)
382 /* mgl: change this to use destfile_fs for correctness and to */
383 /* handle the case where dccwithnick is set */
384 move_file_utf8 (prefs.dccdir, prefs.dcc_completed_dir,
385 file_part (dcc->destfile), prefs.dccpermissions);
391 dcc->dccstat = dccstat;
392 if (dcc->dccchat)
394 free (dcc->dccchat);
395 dcc->dccchat = NULL;
398 if (destroy)
400 dcc_list = g_slist_remove (dcc_list, dcc);
401 fe_dcc_remove (dcc);
402 if (dcc->proxy)
403 free (dcc->proxy);
404 if (dcc->file)
405 free (dcc->file);
406 if (dcc->destfile)
407 g_free (dcc->destfile);
408 if (dcc->destfile_fs)
409 g_free (dcc->destfile_fs);
410 free (dcc->nick);
411 free (dcc);
412 return;
415 fe_dcc_update (dcc);
418 void
419 dcc_abort (session *sess, struct DCC *dcc)
421 if (dcc)
423 switch (dcc->dccstat)
425 case STAT_QUEUED:
426 case STAT_CONNECTING:
427 case STAT_ACTIVE:
428 dcc_close (dcc, STAT_ABORTED, FALSE);
429 switch (dcc->type)
431 case TYPE_CHATSEND:
432 case TYPE_CHATRECV:
433 EMIT_SIGNAL (XP_TE_DCCCHATABORT, sess, dcc->nick, NULL, NULL,
434 NULL, 0);
435 break;
436 case TYPE_SEND:
437 EMIT_SIGNAL (XP_TE_DCCSENDABORT, sess, dcc->nick,
438 file_part (dcc->file), NULL, NULL, 0);
439 break;
440 case TYPE_RECV:
441 EMIT_SIGNAL (XP_TE_DCCRECVABORT, sess, dcc->nick,
442 dcc->file, NULL, NULL, 0);
444 break;
445 default:
446 dcc_close (dcc, 0, TRUE);
451 void
452 dcc_notify_kill (struct server *serv)
454 struct server *replaceserv = 0;
455 struct DCC *dcc;
456 GSList *list = dcc_list;
457 if (serv_list)
458 replaceserv = (struct server *) serv_list->data;
459 while (list)
461 dcc = (struct DCC *) list->data;
462 if (dcc->serv == serv)
463 dcc->serv = replaceserv;
464 list = list->next;
468 struct DCC *
469 dcc_write_chat (char *nick, char *text)
471 struct DCC *dcc;
472 int len;
474 dcc = find_dcc (nick, "", TYPE_CHATRECV);
475 if (!dcc)
476 dcc = find_dcc (nick, "", TYPE_CHATSEND);
477 if (dcc && dcc->dccstat == STAT_ACTIVE)
479 len = strlen (text);
480 tcp_send_real (NULL, dcc->sok, dcc->serv->encoding, dcc->serv->using_irc,
481 text, len);
482 send (dcc->sok, "\n", 1, 0);
483 dcc->size += len;
484 fe_dcc_update (dcc);
485 return dcc;
487 return 0;
490 /* returns: 0 - ok
491 1 - the dcc is closed! */
493 static int
494 dcc_chat_line (struct DCC *dcc, char *line)
496 session *sess;
497 char *word[PDIWORDS];
498 char *po;
499 char *utf;
500 char *conv;
501 int ret, i;
502 int len;
503 gsize utf_len;
504 char portbuf[32];
506 len = strlen (line);
507 if (dcc->serv->using_cp1255)
508 len++; /* include the NUL terminator */
510 if (dcc->serv->using_irc) /* using "IRC" encoding (CP1252/UTF-8 hybrid) */
511 utf = NULL;
512 else if (dcc->serv->encoding == NULL) /* system */
513 utf = g_locale_to_utf8 (line, len, NULL, &utf_len, NULL);
514 else
515 utf = g_convert (line, len, "UTF-8", dcc->serv->encoding, 0, &utf_len, 0);
517 if (utf)
519 line = utf;
520 len = utf_len;
523 if (dcc->serv->using_cp1255 && len > 0)
524 len--;
526 /* we really need valid UTF-8 now */
527 conv = text_validate (&line, &len);
529 sess = find_dialog (dcc->serv, dcc->nick);
530 if (!sess)
531 sess = dcc->serv->front_session;
533 sprintf (portbuf, "%d", dcc->port);
535 word[0] = "DCC Chat Text";
536 word[1] = net_ip (dcc->addr);
537 word[2] = portbuf;
538 word[3] = dcc->nick;
539 word[4] = line;
540 for (i = 5; i < PDIWORDS; i++)
541 word[i] = "\000";
543 ret = plugin_emit_print (sess, word);
545 /* did the plugin close it? */
546 if (!g_slist_find (dcc_list, dcc))
548 if (utf)
549 g_free (utf);
550 if (conv)
551 g_free (conv);
552 return 1;
555 /* did the plugin eat the event? */
556 if (ret)
558 if (utf)
559 g_free (utf);
560 if (conv)
561 g_free (conv);
562 return 0;
565 url_check_line (line, len);
567 if (line[0] == 1 && !strncasecmp (line + 1, "ACTION", 6))
569 po = strchr (line + 8, '\001');
570 if (po)
571 po[0] = 0;
572 inbound_action (sess, dcc->serv->nick, dcc->nick, "", line + 8, FALSE, FALSE);
573 } else
575 inbound_privmsg (dcc->serv, dcc->nick, "", line, FALSE);
577 if (utf)
578 g_free (utf);
579 if (conv)
580 g_free (conv);
581 return 0;
584 static gboolean
585 dcc_read_chat (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
587 int i, len, dead;
588 char portbuf[32];
589 char lbuf[2050];
591 while (1)
593 if (dcc->throttled)
595 fe_input_remove (dcc->iotag);
596 dcc->iotag = 0;
597 return FALSE;
600 if (!dcc->iotag)
601 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX, dcc_read_chat, dcc);
603 len = recv (dcc->sok, lbuf, sizeof (lbuf) - 2, 0);
604 if (len < 1)
606 if (len < 0)
608 if (would_block ())
609 return TRUE;
611 sprintf (portbuf, "%d", dcc->port);
612 EMIT_SIGNAL (XP_TE_DCCCHATF, dcc->serv->front_session, dcc->nick,
613 net_ip (dcc->addr), portbuf,
614 errorstring ((len < 0) ? sock_error () : 0), 0);
615 dcc_close (dcc, STAT_FAILED, FALSE);
616 return TRUE;
618 i = 0;
619 lbuf[len] = 0;
620 while (i < len)
622 switch (lbuf[i])
624 case '\r':
625 break;
626 case '\n':
627 dcc->dccchat->linebuf[dcc->dccchat->pos] = 0;
628 dead = dcc_chat_line (dcc, dcc->dccchat->linebuf);
630 if (dead || !dcc->dccchat) /* the dcc has been closed, don't use (DCC *)! */
631 return TRUE;
633 dcc->pos += dcc->dccchat->pos;
634 dcc->dccchat->pos = 0;
635 fe_dcc_update (dcc);
636 break;
637 default:
638 dcc->dccchat->linebuf[dcc->dccchat->pos] = lbuf[i];
639 if (dcc->dccchat->pos < (sizeof (dcc->dccchat->linebuf) - 1))
640 dcc->dccchat->pos++;
642 i++;
647 static void
648 dcc_calc_average_cps (struct DCC *dcc)
650 time_t sec;
652 sec = time (0) - dcc->starttime;
653 if (sec < 1)
654 sec = 1;
655 if (dcc->type == TYPE_SEND)
656 dcc->cps = (dcc->ack - dcc->resumable) / sec;
657 else
658 dcc->cps = (dcc->pos - dcc->resumable) / sec;
661 static void
662 dcc_send_ack (struct DCC *dcc)
664 /* send in 32-bit big endian */
665 guint32 pos = htonl (dcc->pos & 0xffffffff);
666 send (dcc->sok, (char *) &pos, 4, 0);
669 static gboolean
670 dcc_read (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
672 char *old;
673 char buf[4096];
674 int n;
675 gboolean need_ack = FALSE;
677 if (dcc->fp == -1)
680 /* try to create the download dir (even if it exists, no harm) */
681 mkdir_utf8 (prefs.dccdir);
683 if (dcc->resumable)
685 dcc->fp = open (dcc->destfile_fs, O_WRONLY | O_APPEND | OFLAGS);
686 dcc->pos = dcc->resumable;
687 dcc->ack = dcc->resumable;
688 } else
690 if (access (dcc->destfile_fs, F_OK) == 0)
692 n = 0;
695 n++;
696 snprintf (buf, sizeof (buf), "%s.%d", dcc->destfile_fs, n);
698 while (access (buf, F_OK) == 0);
700 g_free (dcc->destfile_fs);
701 dcc->destfile_fs = g_strdup (buf);
703 old = dcc->destfile;
704 dcc->destfile = xchat_filename_to_utf8 (buf, -1, 0, 0, 0);
706 EMIT_SIGNAL (XP_TE_DCCRENAME, dcc->serv->front_session,
707 old, dcc->destfile, NULL, NULL, 0);
708 g_free (old);
710 dcc->fp =
711 open (dcc->destfile_fs, OFLAGS | O_TRUNC | O_WRONLY | O_CREAT,
712 prefs.dccpermissions);
715 if (dcc->fp == -1)
717 /* the last executed function is open(), errno should be valid */
718 EMIT_SIGNAL (XP_TE_DCCFILEERR, dcc->serv->front_session, dcc->destfile,
719 errorstring (errno), NULL, NULL, 0);
720 dcc_close (dcc, STAT_FAILED, FALSE);
721 return TRUE;
723 while (1)
725 if (dcc->throttled)
727 if (need_ack)
728 dcc_send_ack (dcc);
730 fe_input_remove (dcc->iotag);
731 dcc->iotag = 0;
732 return FALSE;
735 if (!dcc->iotag)
736 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX, dcc_read, dcc);
738 n = recv (dcc->sok, buf, sizeof (buf), 0);
739 if (n < 1)
741 if (n < 0)
743 if (would_block ())
745 if (need_ack)
746 dcc_send_ack (dcc);
747 return TRUE;
750 EMIT_SIGNAL (XP_TE_DCCRECVERR, dcc->serv->front_session, dcc->file,
751 dcc->destfile, dcc->nick,
752 errorstring ((n < 0) ? sock_error () : 0), 0);
753 /* send ack here? but the socket is dead */
754 /*if (need_ack)
755 dcc_send_ack (dcc);*/
756 dcc_close (dcc, STAT_FAILED, FALSE);
757 return TRUE;
760 if (write (dcc->fp, buf, n) == -1) /* could be out of hdd space */
762 EMIT_SIGNAL (XP_TE_DCCRECVERR, dcc->serv->front_session, dcc->file,
763 dcc->destfile, dcc->nick, errorstring (errno), 0);
764 if (need_ack)
765 dcc_send_ack (dcc);
766 dcc_close (dcc, STAT_FAILED, FALSE);
767 return TRUE;
770 dcc->lasttime = time (0);
771 dcc->pos += n;
772 need_ack = TRUE; /* send ack when we're done recv()ing */
774 if (dcc->pos >= dcc->size)
776 dcc_send_ack (dcc);
777 dcc_close (dcc, STAT_DONE, FALSE);
778 dcc_calc_average_cps (dcc); /* this must be done _after_ dcc_close, or dcc_remove_from_sum will see the wrong value in dcc->cps */
779 sprintf (buf, "%d", dcc->cps);
780 EMIT_SIGNAL (XP_TE_DCCRECVCOMP, dcc->serv->front_session,
781 dcc->file, dcc->destfile, dcc->nick, buf, 0);
782 return TRUE;
787 static void
788 dcc_open_query (server *serv, char *nick)
790 if (prefs.autodialog)
791 open_query (serv, nick, FALSE);
794 static gboolean
795 dcc_did_connect (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
797 int er;
798 struct sockaddr_in addr;
800 memset (&addr, 0, sizeof (addr));
801 addr.sin_port = htons (dcc->port);
802 addr.sin_family = AF_INET;
803 addr.sin_addr.s_addr = htonl (dcc->addr);
805 /* check if it's already connected; This always fails on winXP */
806 if (connect (dcc->sok, (struct sockaddr *) &addr, sizeof (addr)) != 0)
808 er = sock_error ();
809 if (er != EISCONN)
811 EMIT_SIGNAL (XP_TE_DCCCONFAIL, dcc->serv->front_session,
812 dcctypes[dcc->type], dcc->nick, errorstring (er),
813 NULL, 0);
814 dcc->dccstat = STAT_FAILED;
815 fe_dcc_update (dcc);
816 return FALSE;
820 return TRUE;
823 static gboolean
824 dcc_connect_finished (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
826 char host[128];
828 if (dcc->iotag)
830 fe_input_remove (dcc->iotag);
831 dcc->iotag = 0;
834 if (!dcc_did_connect (source, condition, dcc))
835 return TRUE;
837 dcc->dccstat = STAT_ACTIVE;
838 snprintf (host, sizeof host, "%s:%d", net_ip (dcc->addr), dcc->port);
840 switch (dcc->type)
842 case TYPE_RECV:
843 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX, dcc_read, dcc);
844 EMIT_SIGNAL (XP_TE_DCCCONRECV, dcc->serv->front_session,
845 dcc->nick, host, dcc->file, NULL, 0);
846 break;
847 case TYPE_SEND:
848 /* passive send */
849 dcc->fastsend = prefs.fastdccsend;
850 if (dcc->fastsend)
851 dcc->wiotag = fe_input_add (dcc->sok, FIA_WRITE, dcc_send_data, dcc);
852 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX, dcc_read_ack, dcc);
853 dcc_send_data (NULL, 0, (gpointer)dcc);
854 EMIT_SIGNAL (XP_TE_DCCCONSEND, dcc->serv->front_session,
855 dcc->nick, host, dcc->file, NULL, 0);
856 break;
857 case TYPE_CHATSEND: /* pchat */
858 dcc_open_query (dcc->serv, dcc->nick);
859 case TYPE_CHATRECV: /* normal chat */
860 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX, dcc_read_chat, dcc);
861 dcc->dccchat = malloc (sizeof (struct dcc_chat));
862 dcc->dccchat->pos = 0;
863 EMIT_SIGNAL (XP_TE_DCCCONCHAT, dcc->serv->front_session,
864 dcc->nick, host, NULL, NULL, 0);
865 break;
867 dcc->starttime = time (0);
868 dcc->lasttime = dcc->starttime;
869 fe_dcc_update (dcc);
871 return TRUE;
874 static gboolean
875 read_proxy (struct DCC *dcc)
877 struct proxy_state *proxy = dcc->proxy;
878 while (proxy->bufferused < proxy->buffersize)
880 int ret = recv (dcc->sok, &proxy->buffer[proxy->bufferused],
881 proxy->buffersize - proxy->bufferused, 0);
882 if (ret > 0)
883 proxy->bufferused += ret;
884 else
886 if (would_block ())
887 return FALSE;
888 else
890 dcc->dccstat = STAT_FAILED;
891 fe_dcc_update (dcc);
892 if (dcc->iotag)
894 fe_input_remove (dcc->iotag);
895 dcc->iotag = 0;
897 return FALSE;
901 return TRUE;
904 static gboolean
905 write_proxy (struct DCC *dcc)
907 struct proxy_state *proxy = dcc->proxy;
908 while (proxy->bufferused < proxy->buffersize)
910 int ret = send (dcc->sok, &proxy->buffer[proxy->bufferused],
911 proxy->buffersize - proxy->bufferused, 0);
912 if (ret >= 0)
913 proxy->bufferused += ret;
914 else
916 if (would_block ())
917 return FALSE;
918 else
920 dcc->dccstat = STAT_FAILED;
921 fe_dcc_update (dcc);
922 if (dcc->wiotag)
924 fe_input_remove (dcc->wiotag);
925 dcc->wiotag = 0;
927 return FALSE;
931 return TRUE;
934 static gboolean
935 proxy_read_line (struct DCC *dcc)
937 struct proxy_state *proxy = dcc->proxy;
938 while (1)
940 proxy->buffersize = proxy->bufferused + 1;
941 if (!read_proxy (dcc))
942 return FALSE;
943 if (proxy->buffer[proxy->bufferused - 1] == '\n'
944 || proxy->bufferused == MAX_PROXY_BUFFER)
946 proxy->buffer[proxy->bufferused - 1] = 0;
947 return TRUE;
952 static gboolean
953 dcc_wingate_proxy_traverse (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
955 struct proxy_state *proxy = dcc->proxy;
956 if (proxy->phase == 0)
958 proxy->buffersize = snprintf ((char*) proxy->buffer, MAX_PROXY_BUFFER,
959 "%s %d\r\n", net_ip(dcc->addr),
960 dcc->port);
961 proxy->bufferused = 0;
962 dcc->wiotag = fe_input_add (dcc->sok, FIA_WRITE|FIA_EX,
963 dcc_wingate_proxy_traverse, dcc);
964 ++proxy->phase;
966 if (proxy->phase == 1)
968 if (!read_proxy (dcc))
969 return TRUE;
970 fe_input_remove (dcc->wiotag);
971 dcc->wiotag = 0;
972 dcc_connect_finished (source, 0, dcc);
974 return TRUE;
977 struct sock_connect
979 char version;
980 char type;
981 guint16 port;
982 guint32 address;
983 char username[10];
985 static gboolean
986 dcc_socks_proxy_traverse (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
988 struct proxy_state *proxy = dcc->proxy;
990 if (proxy->phase == 0)
992 struct sock_connect sc;
993 sc.version = 4;
994 sc.type = 1;
995 sc.port = htons (dcc->port);
996 sc.address = htonl (dcc->addr);
997 strncpy (sc.username, prefs.username, 9);
998 memcpy (proxy->buffer, &sc, sizeof (sc));
999 proxy->buffersize = 8 + strlen (sc.username) + 1;
1000 proxy->bufferused = 0;
1001 dcc->wiotag = fe_input_add (dcc->sok, FIA_WRITE|FIA_EX,
1002 dcc_socks_proxy_traverse, dcc);
1003 ++proxy->phase;
1006 if (proxy->phase == 1)
1008 if (!write_proxy (dcc))
1009 return TRUE;
1010 fe_input_remove (dcc->wiotag);
1011 dcc->wiotag = 0;
1012 proxy->bufferused = 0;
1013 proxy->buffersize = 8;
1014 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX,
1015 dcc_socks_proxy_traverse, dcc);
1016 ++proxy->phase;
1019 if (proxy->phase == 2)
1021 if (!read_proxy (dcc))
1022 return TRUE;
1023 fe_input_remove (dcc->iotag);
1024 dcc->iotag = 0;
1025 if (proxy->buffer[1] == 90)
1026 dcc_connect_finished (source, 0, dcc);
1027 else
1029 dcc->dccstat = STAT_FAILED;
1030 fe_dcc_update (dcc);
1034 return TRUE;
1037 struct sock5_connect1
1039 char version;
1040 char nmethods;
1041 char method;
1043 static gboolean
1044 dcc_socks5_proxy_traverse (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
1046 struct proxy_state *proxy = dcc->proxy;
1047 int auth = prefs.proxy_auth && prefs.proxy_user[0] && prefs.proxy_pass[0];
1049 if (proxy->phase == 0)
1051 struct sock5_connect1 sc1;
1053 sc1.version = 5;
1054 sc1.nmethods = 1;
1055 sc1.method = 0;
1056 if (auth)
1057 sc1.method = 2;
1058 memcpy (proxy->buffer, &sc1, 3);
1059 proxy->buffersize = 3;
1060 proxy->bufferused = 0;
1061 dcc->wiotag = fe_input_add (dcc->sok, FIA_WRITE|FIA_EX,
1062 dcc_socks5_proxy_traverse, dcc);
1063 ++proxy->phase;
1066 if (proxy->phase == 1)
1068 if (!write_proxy (dcc))
1069 return TRUE;
1070 fe_input_remove (dcc->wiotag);
1071 dcc->wiotag = 0;
1072 proxy->bufferused = 0;
1073 proxy->buffersize = 2;
1074 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX,
1075 dcc_socks5_proxy_traverse, dcc);
1076 ++proxy->phase;
1079 if (proxy->phase == 2)
1081 if (!read_proxy (dcc))
1082 return TRUE;
1083 fe_input_remove (dcc->iotag);
1084 dcc->iotag = 0;
1086 /* did the server say no auth required? */
1087 if (proxy->buffer[0] == 5 && proxy->buffer[1] == 0)
1088 auth = 0;
1090 /* Set up authentication I/O */
1091 if (auth)
1093 int len_u=0, len_p=0;
1095 /* authentication sub-negotiation (RFC1929) */
1096 if ( proxy->buffer[0] != 5 || proxy->buffer[1] != 2 ) /* UPA not supported by server */
1098 PrintText (dcc->serv->front_session, "SOCKS\tServer doesn't support UPA authentication.\n");
1099 dcc->dccstat = STAT_FAILED;
1100 fe_dcc_update (dcc);
1101 return TRUE;
1104 memset (proxy->buffer, 0, MAX_PROXY_BUFFER);
1106 /* form the UPA request */
1107 len_u = strlen (prefs.proxy_user);
1108 len_p = strlen (prefs.proxy_pass);
1109 proxy->buffer[0] = 1;
1110 proxy->buffer[1] = len_u;
1111 memcpy (proxy->buffer + 2, prefs.proxy_user, len_u);
1112 proxy->buffer[2 + len_u] = len_p;
1113 memcpy (proxy->buffer + 3 + len_u, prefs.proxy_pass, len_p);
1115 proxy->buffersize = 3 + len_u + len_p;
1116 proxy->bufferused = 0;
1117 dcc->wiotag = fe_input_add (dcc->sok, FIA_WRITE|FIA_EX,
1118 dcc_socks5_proxy_traverse, dcc);
1119 ++proxy->phase;
1121 else
1123 if (proxy->buffer[0] != 5 || proxy->buffer[1] != 0)
1125 PrintText (dcc->serv->front_session, "SOCKS\tAuthentication required but disabled in settings.\n");
1126 dcc->dccstat = STAT_FAILED;
1127 fe_dcc_update (dcc);
1128 return TRUE;
1130 proxy->phase += 2;
1134 if (proxy->phase == 3)
1136 if (!write_proxy (dcc))
1137 return TRUE;
1138 fe_input_remove (dcc->wiotag);
1139 dcc->wiotag = 0;
1140 proxy->buffersize = 2;
1141 proxy->bufferused = 0;
1142 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX,
1143 dcc_socks5_proxy_traverse, dcc);
1144 ++proxy->phase;
1147 if (proxy->phase == 4)
1149 if (!read_proxy (dcc))
1150 return TRUE;
1151 if (dcc->iotag)
1153 fe_input_remove (dcc->iotag);
1154 dcc->iotag = 0;
1156 if (proxy->buffer[1] != 0)
1158 PrintText (dcc->serv->front_session, "SOCKS\tAuthentication failed. "
1159 "Is username and password correct?\n");
1160 dcc->dccstat = STAT_FAILED;
1161 fe_dcc_update (dcc);
1162 return TRUE;
1164 ++proxy->phase;
1167 if (proxy->phase == 5)
1169 proxy->buffer[0] = 5; /* version (socks 5) */
1170 proxy->buffer[1] = 1; /* command (connect) */
1171 proxy->buffer[2] = 0; /* reserved */
1172 proxy->buffer[3] = 1; /* address type (IPv4) */
1173 proxy->buffer[4] = (dcc->addr >> 24) & 0xFF; /* IP address */
1174 proxy->buffer[5] = (dcc->addr >> 16) & 0xFF;
1175 proxy->buffer[6] = (dcc->addr >> 8) & 0xFF;
1176 proxy->buffer[7] = (dcc->addr & 0xFF);
1177 proxy->buffer[8] = (dcc->port >> 8) & 0xFF; /* port */
1178 proxy->buffer[9] = (dcc->port & 0xFF);
1179 proxy->buffersize = 10;
1180 proxy->bufferused = 0;
1181 dcc->wiotag = fe_input_add (dcc->sok, FIA_WRITE|FIA_EX,
1182 dcc_socks5_proxy_traverse, dcc);
1183 ++proxy->phase;
1186 if (proxy->phase == 6)
1188 if (!write_proxy (dcc))
1189 return TRUE;
1190 fe_input_remove (dcc->wiotag);
1191 dcc->wiotag = 0;
1192 proxy->buffersize = 4;
1193 proxy->bufferused = 0;
1194 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX,
1195 dcc_socks5_proxy_traverse, dcc);
1196 ++proxy->phase;
1199 if (proxy->phase == 7)
1201 if (!read_proxy (dcc))
1202 return TRUE;
1203 if (proxy->buffer[0] != 5 || proxy->buffer[1] != 0)
1205 fe_input_remove (dcc->iotag);
1206 dcc->iotag = 0;
1207 if (proxy->buffer[1] == 2)
1208 PrintText (dcc->serv->front_session, "SOCKS\tProxy refused to connect to host (not allowed).\n");
1209 else
1210 PrintTextf (dcc->serv->front_session, "SOCKS\tProxy failed to connect to host (error %d).\n", proxy->buffer[1]);
1211 dcc->dccstat = STAT_FAILED;
1212 fe_dcc_update (dcc);
1213 return TRUE;
1215 switch (proxy->buffer[3])
1217 case 1: proxy->buffersize += 6; break;
1218 case 3: proxy->buffersize += 1; break;
1219 case 4: proxy->buffersize += 18; break;
1221 ++proxy->phase;
1224 if (proxy->phase == 8)
1226 if (!read_proxy (dcc))
1227 return TRUE;
1228 /* handle domain name case */
1229 if (proxy->buffer[3] == 3)
1231 proxy->buffersize = 5 + proxy->buffer[4] + 2;
1233 /* everything done? */
1234 if (proxy->bufferused == proxy->buffersize)
1236 fe_input_remove (dcc->iotag);
1237 dcc->iotag = 0;
1238 dcc_connect_finished (source, 0, dcc);
1241 return TRUE;
1244 static gboolean
1245 dcc_http_proxy_traverse (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
1247 struct proxy_state *proxy = dcc->proxy;
1249 if (proxy->phase == 0)
1251 char buf[256];
1252 char auth_data[128];
1253 char auth_data2[68];
1254 int n, n2;
1256 n = snprintf (buf, sizeof (buf), "CONNECT %s:%d HTTP/1.0\r\n",
1257 net_ip(dcc->addr), dcc->port);
1258 if (prefs.proxy_auth)
1260 n2 = snprintf (auth_data2, sizeof (auth_data2), "%s:%s",
1261 prefs.proxy_user, prefs.proxy_pass);
1262 base64_encode (auth_data, auth_data2, n2);
1263 n += snprintf (buf+n, sizeof (buf)-n, "Proxy-Authorization: Basic %s\r\n", auth_data);
1265 n += snprintf (buf+n, sizeof (buf)-n, "\r\n");
1266 proxy->buffersize = n;
1267 proxy->bufferused = 0;
1268 memcpy (proxy->buffer, buf, proxy->buffersize);
1269 dcc->wiotag = fe_input_add (dcc->sok, FIA_WRITE|FIA_EX,
1270 dcc_http_proxy_traverse, dcc);
1271 ++proxy->phase;
1274 if (proxy->phase == 1)
1276 if (!write_proxy (dcc))
1277 return TRUE;
1278 fe_input_remove (dcc->wiotag);
1279 dcc->wiotag = 0;
1280 proxy->bufferused = 0;
1281 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX,
1282 dcc_http_proxy_traverse, dcc);
1283 ++proxy->phase;
1286 if (proxy->phase == 2)
1288 if (!proxy_read_line (dcc))
1289 return TRUE;
1290 /* "HTTP/1.0 200 OK" */
1291 if (proxy->bufferused < 12 ||
1292 memcmp (proxy->buffer, "HTTP/", 5) || memcmp (proxy->buffer + 9, "200", 3))
1294 fe_input_remove (dcc->iotag);
1295 dcc->iotag = 0;
1296 PrintText (dcc->serv->front_session, proxy->buffer);
1297 dcc->dccstat = STAT_FAILED;
1298 fe_dcc_update (dcc);
1299 return TRUE;
1301 proxy->bufferused = 0;
1302 ++proxy->phase;
1305 if (proxy->phase == 3)
1307 while (1)
1309 /* read until blank line */
1310 if (proxy_read_line (dcc))
1312 if (proxy->bufferused < 1 ||
1313 (proxy->bufferused == 2 && proxy->buffer[0] == '\r'))
1315 break;
1317 if (proxy->bufferused > 1)
1318 PrintText (dcc->serv->front_session, proxy->buffer);
1319 proxy->bufferused = 0;
1321 else
1322 return TRUE;
1324 fe_input_remove (dcc->iotag);
1325 dcc->iotag = 0;
1326 dcc_connect_finished (source, 0, dcc);
1329 return TRUE;
1332 static gboolean
1333 dcc_proxy_connect (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
1335 fe_input_remove (dcc->iotag);
1336 dcc->iotag = 0;
1338 if (!dcc_did_connect (source, condition, dcc))
1339 return TRUE;
1341 dcc->proxy = malloc (sizeof (struct proxy_state));
1342 if (!dcc->proxy)
1344 dcc->dccstat = STAT_FAILED;
1345 fe_dcc_update (dcc);
1346 return TRUE;
1348 memset (dcc->proxy, 0, sizeof (struct proxy_state));
1350 switch (prefs.proxy_type)
1352 case 1: return dcc_wingate_proxy_traverse (source, condition, dcc);
1353 case 2: return dcc_socks_proxy_traverse (source, condition, dcc);
1354 case 3: return dcc_socks5_proxy_traverse (source, condition, dcc);
1355 case 4: return dcc_http_proxy_traverse (source, condition, dcc);
1357 return TRUE;
1360 static int dcc_listen_init (struct DCC *, struct session *);
1362 static void
1363 dcc_connect (struct DCC *dcc)
1365 int ret;
1366 char tbuf[400];
1368 if (dcc->dccstat == STAT_CONNECTING)
1369 return;
1370 dcc->dccstat = STAT_CONNECTING;
1372 if (dcc->pasvid && dcc->port == 0)
1374 /* accepted a passive dcc send */
1375 ret = dcc_listen_init (dcc, dcc->serv->front_session);
1376 if (!ret)
1378 dcc_close (dcc, STAT_FAILED, FALSE);
1379 return;
1381 /* possible problems with filenames containing spaces? */
1382 if (dcc->type == TYPE_RECV)
1383 snprintf (tbuf, sizeof (tbuf), strchr (dcc->file, ' ') ?
1384 "DCC SEND \"%s\" %u %d %"DCC_SFMT" %d" :
1385 "DCC SEND %s %u %d %"DCC_SFMT" %d", dcc->file,
1386 dcc->addr, dcc->port, dcc->size, dcc->pasvid);
1387 else
1388 snprintf (tbuf, sizeof (tbuf), "DCC CHAT chat %u %d %d",
1389 dcc->addr, dcc->port, dcc->pasvid);
1390 dcc->serv->p_ctcp (dcc->serv, dcc->nick, tbuf);
1392 else
1394 dcc->sok = dcc_connect_sok (dcc);
1395 if (dcc->sok == -1)
1397 dcc->dccstat = STAT_FAILED;
1398 fe_dcc_update (dcc);
1399 return;
1401 if (DCC_USE_PROXY ())
1402 dcc->iotag = fe_input_add (dcc->sok, FIA_WRITE|FIA_EX, dcc_proxy_connect, dcc);
1403 else
1404 dcc->iotag = fe_input_add (dcc->sok, FIA_WRITE|FIA_EX, dcc_connect_finished, dcc);
1407 fe_dcc_update (dcc);
1410 static gboolean
1411 dcc_send_data (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
1413 char *buf;
1414 int len, sent, sok = dcc->sok;
1416 if (prefs.dcc_blocksize < 1) /* this is too little! */
1417 prefs.dcc_blocksize = 1024;
1419 if (prefs.dcc_blocksize > 102400) /* this is too much! */
1420 prefs.dcc_blocksize = 102400;
1422 if (dcc->throttled)
1424 fe_input_remove (dcc->wiotag);
1425 dcc->wiotag = 0;
1426 return FALSE;
1429 if (!dcc->fastsend)
1431 if (dcc->ack < dcc->pos)
1432 return TRUE;
1434 else if (!dcc->wiotag)
1435 dcc->wiotag = fe_input_add (sok, FIA_WRITE, dcc_send_data, dcc);
1437 buf = malloc (prefs.dcc_blocksize);
1438 if (!buf)
1439 return TRUE;
1441 lseek (dcc->fp, dcc->pos, SEEK_SET);
1442 len = read (dcc->fp, buf, prefs.dcc_blocksize);
1443 if (len < 1)
1444 goto abortit;
1445 sent = send (sok, buf, len, 0);
1447 if (sent < 0 && !(would_block ()))
1449 abortit:
1450 free (buf);
1451 EMIT_SIGNAL (XP_TE_DCCSENDFAIL, dcc->serv->front_session,
1452 file_part (dcc->file), dcc->nick,
1453 errorstring (sock_error ()), NULL, 0);
1454 dcc_close (dcc, STAT_FAILED, FALSE);
1455 return TRUE;
1457 if (sent > 0)
1459 dcc->pos += sent;
1460 dcc->lasttime = time (0);
1463 /* have we sent it all yet? */
1464 if (dcc->pos >= dcc->size)
1466 /* it's all sent now, so remove the WRITE/SEND handler */
1467 if (dcc->wiotag)
1469 fe_input_remove (dcc->wiotag);
1470 dcc->wiotag = 0;
1474 free (buf);
1476 return TRUE;
1479 static gboolean
1480 dcc_handle_new_ack (struct DCC *dcc)
1482 guint32 ack;
1483 char buf[16];
1484 gboolean done = FALSE;
1486 memcpy (&ack, dcc->ack_buf, 4);
1487 dcc->ack = ntohl (ack);
1489 /* this could mess up when xfering >32bit files */
1490 if (dcc->size <= 0xffffffff)
1492 /* fix for BitchX */
1493 if (dcc->ack < dcc->resumable)
1494 dcc->ackoffset = TRUE;
1495 if (dcc->ackoffset)
1496 dcc->ack += dcc->resumable;
1499 /* DCC complete check */
1500 if (dcc->pos >= dcc->size && dcc->ack >= (dcc->size & 0xffffffff))
1502 dcc->ack = dcc->size; /* force 100% ack for >4 GB */
1503 dcc_close (dcc, STAT_DONE, FALSE);
1504 dcc_calc_average_cps (dcc); /* this must be done _after_ dcc_close, or dcc_remove_from_sum will see the wrong value in dcc->cps */
1505 sprintf (buf, "%d", dcc->cps);
1506 EMIT_SIGNAL (XP_TE_DCCSENDCOMP, dcc->serv->front_session,
1507 file_part (dcc->file), dcc->nick, buf, NULL, 0);
1508 done = TRUE;
1510 else if ((!dcc->fastsend) && (dcc->ack >= (dcc->pos & 0xffffffff)))
1512 dcc_send_data (NULL, 0, (gpointer)dcc);
1515 #ifdef USE_DCC64
1516 /* take the top 32 of "bytes send" and bottom 32 of "ack" */
1517 dcc->ack = (dcc->pos & G_GINT64_CONSTANT (0xffffffff00000000)) |
1518 (dcc->ack & 0xffffffff);
1519 /* dcc->ack is only used for CPS and PERCENTAGE calcs from now on... */
1520 #endif
1522 return done;
1525 static gboolean
1526 dcc_read_ack (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
1528 int len;
1530 while (1)
1532 /* try to fill up 4 bytes */
1533 len = recv (dcc->sok, dcc->ack_buf, 4 - dcc->ack_pos, 0);
1534 if (len < 1)
1536 if (len < 0)
1538 if (would_block ()) /* ok - keep waiting */
1539 return TRUE;
1541 EMIT_SIGNAL (XP_TE_DCCSENDFAIL, dcc->serv->front_session,
1542 file_part (dcc->file), dcc->nick,
1543 errorstring ((len < 0) ? sock_error () : 0), NULL, 0);
1544 dcc_close (dcc, STAT_FAILED, FALSE);
1545 return TRUE;
1548 dcc->ack_pos += len;
1549 if (dcc->ack_pos >= 4)
1551 dcc->ack_pos = 0;
1552 if (dcc_handle_new_ack (dcc))
1553 return TRUE;
1555 /* loop again until would_block() returns true */
1559 static gboolean
1560 dcc_accept (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
1562 char host[128];
1563 struct sockaddr_in CAddr;
1564 int sok;
1565 socklen_t len;
1567 len = sizeof (CAddr);
1568 sok = accept (dcc->sok, (struct sockaddr *) &CAddr, &len);
1569 fe_input_remove (dcc->iotag);
1570 dcc->iotag = 0;
1571 closesocket (dcc->sok);
1572 if (sok < 0)
1574 dcc->sok = -1;
1575 dcc_close (dcc, STAT_FAILED, FALSE);
1576 return TRUE;
1578 set_nonblocking (sok);
1579 dcc->sok = sok;
1580 dcc->addr = ntohl (CAddr.sin_addr.s_addr);
1582 if (dcc->pasvid)
1583 return dcc_connect_finished (NULL, 0, dcc);
1585 dcc->dccstat = STAT_ACTIVE;
1586 dcc->lasttime = dcc->starttime = time (0);
1587 dcc->fastsend = prefs.fastdccsend;
1589 snprintf (host, sizeof (host), "%s:%d", net_ip (dcc->addr), dcc->port);
1591 switch (dcc->type)
1593 case TYPE_SEND:
1594 if (dcc->fastsend)
1595 dcc->wiotag = fe_input_add (sok, FIA_WRITE, dcc_send_data, dcc);
1596 dcc->iotag = fe_input_add (sok, FIA_READ|FIA_EX, dcc_read_ack, dcc);
1597 dcc_send_data (NULL, 0, (gpointer)dcc);
1598 EMIT_SIGNAL (XP_TE_DCCCONSEND, dcc->serv->front_session,
1599 dcc->nick, host, dcc->file, NULL, 0);
1600 break;
1602 case TYPE_CHATSEND:
1603 dcc_open_query (dcc->serv, dcc->nick);
1604 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX, dcc_read_chat, dcc);
1605 dcc->dccchat = malloc (sizeof (struct dcc_chat));
1606 dcc->dccchat->pos = 0;
1607 EMIT_SIGNAL (XP_TE_DCCCONCHAT, dcc->serv->front_session,
1608 dcc->nick, host, NULL, NULL, 0);
1609 break;
1612 fe_dcc_update (dcc);
1614 return TRUE;
1617 guint32
1618 dcc_get_my_address (void) /* the address we'll tell the other person */
1620 struct hostent *dns_query;
1621 guint32 addr = 0;
1623 if (prefs.ip_from_server && prefs.dcc_ip)
1624 addr = prefs.dcc_ip;
1625 else if (prefs.dcc_ip_str[0])
1627 dns_query = gethostbyname ((const char *) prefs.dcc_ip_str);
1629 if (dns_query != NULL &&
1630 dns_query->h_length == 4 &&
1631 dns_query->h_addr_list[0] != NULL)
1633 /*we're offered at least one IPv4 address: we take the first*/
1634 addr = *((guint32*) dns_query->h_addr_list[0]);
1638 return addr;
1641 static int
1642 dcc_listen_init (struct DCC *dcc, session *sess)
1644 guint32 my_addr;
1645 struct sockaddr_in SAddr;
1646 int i, bindretval = -1;
1647 socklen_t len;
1649 dcc->sok = socket (AF_INET, SOCK_STREAM, 0);
1650 if (dcc->sok == -1)
1651 return FALSE;
1653 memset (&SAddr, 0, sizeof (struct sockaddr_in));
1655 len = sizeof (SAddr);
1656 getsockname (dcc->serv->sok, (struct sockaddr *) &SAddr, &len);
1658 SAddr.sin_family = AF_INET;
1660 /*if local_ip is specified use that*/
1661 if (prefs.local_ip != 0xffffffff)
1663 my_addr = prefs.local_ip;
1664 SAddr.sin_addr.s_addr = prefs.local_ip;
1666 /*otherwise use the default*/
1667 else
1668 my_addr = SAddr.sin_addr.s_addr;
1670 /*if we have a valid portrange try to use that*/
1671 if (prefs.first_dcc_send_port > 0)
1673 SAddr.sin_port = 0;
1674 i = 0;
1675 while ((prefs.last_dcc_send_port > ntohs(SAddr.sin_port)) &&
1676 (bindretval == -1))
1678 SAddr.sin_port = htons (prefs.first_dcc_send_port + i);
1679 i++;
1680 /*printf("Trying to bind against port: %d\n",ntohs(SAddr.sin_port));*/
1681 bindretval = bind (dcc->sok, (struct sockaddr *) &SAddr, sizeof (SAddr));
1684 /* with a small port range, reUseAddr is needed */
1685 len = 1;
1686 setsockopt (dcc->sok, SOL_SOCKET, SO_REUSEADDR, (char *) &len, sizeof (len));
1688 } else
1690 /* try random port */
1691 SAddr.sin_port = 0;
1692 bindretval = bind (dcc->sok, (struct sockaddr *) &SAddr, sizeof (SAddr));
1695 if (bindretval == -1)
1697 /* failed to bind */
1698 PrintText (sess, "Failed to bind to any address or port.\n");
1699 return FALSE;
1702 len = sizeof (SAddr);
1703 getsockname (dcc->sok, (struct sockaddr *) &SAddr, &len);
1705 dcc->port = ntohs (SAddr.sin_port);
1707 /*if we have a dcc_ip, we use that, so the remote client can connect*/
1708 /*else we try to take an address from dcc_ip_str*/
1709 /*if something goes wrong we tell the client to connect to our LAN ip*/
1710 dcc->addr = dcc_get_my_address ();
1712 /*if nothing else worked we use the address we bound to*/
1713 if (dcc->addr == 0)
1714 dcc->addr = my_addr;
1716 dcc->addr = ntohl (dcc->addr);
1718 set_nonblocking (dcc->sok);
1719 listen (dcc->sok, 1);
1720 set_blocking (dcc->sok);
1722 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX, dcc_accept, dcc);
1724 return TRUE;
1727 static struct session *dccsess;
1728 static char *dccto; /* lame!! */
1729 static int dccmaxcps;
1730 static int recursive = FALSE;
1732 static void
1733 dcc_send_wild (char *file)
1735 dcc_send (dccsess, dccto, file, dccmaxcps, 0);
1738 void
1739 dcc_send (struct session *sess, char *to, char *file, int maxcps, int passive)
1741 char outbuf[512];
1742 struct stat st;
1743 struct DCC *dcc;
1744 char *file_fs;
1746 /* this is utf8 */
1747 file = expand_homedir (file);
1749 if (!recursive && (strchr (file, '*') || strchr (file, '?')))
1751 char path[256];
1752 char wild[256];
1753 char *path_fs; /* local filesystem encoding */
1755 safe_strcpy (wild, file_part (file), sizeof (wild));
1756 path_part (file, path, sizeof (path));
1757 if (path[0] != '/' || path[1] != '\0')
1758 path[strlen (path) - 1] = 0; /* remove trailing slash */
1760 dccsess = sess;
1761 dccto = to;
1762 dccmaxcps = maxcps;
1764 free (file);
1766 /* for_files() will use opendir, so we need local FS encoding */
1767 path_fs = xchat_filename_from_utf8 (path, -1, 0, 0, 0);
1768 if (path_fs)
1770 recursive = TRUE;
1771 for_files (path_fs, wild, dcc_send_wild);
1772 recursive = FALSE;
1773 g_free (path_fs);
1776 return;
1779 dcc = new_dcc ();
1780 if (!dcc)
1781 return;
1782 dcc->file = file;
1783 dcc->maxcps = maxcps;
1785 /* get the local filesystem encoding */
1786 file_fs = xchat_filename_from_utf8 (file, -1, 0, 0, 0);
1788 if (stat (file_fs, &st) != -1)
1791 #ifndef USE_DCC64
1792 if (sizeof (st.st_size) > 4 && st.st_size > 4294967295U)
1794 PrintText (sess, "Cannot send files larger than 4 GB.\n");
1795 goto xit;
1797 #endif
1799 if (!(*file_part (file_fs)) || S_ISDIR (st.st_mode) || st.st_size < 1)
1801 PrintText (sess, "Cannot send directories or empty files.\n");
1802 goto xit;
1805 dcc->starttime = dcc->offertime = time (0);
1806 dcc->serv = sess->server;
1807 dcc->dccstat = STAT_QUEUED;
1808 dcc->size = st.st_size;
1809 dcc->type = TYPE_SEND;
1810 dcc->fp = open (file_fs, OFLAGS | O_RDONLY);
1811 if (dcc->fp != -1)
1813 g_free (file_fs);
1814 if (passive || dcc_listen_init (dcc, sess))
1816 char havespaces = 0;
1817 file = dcc->file;
1818 while (*file)
1820 if (*file == ' ')
1822 if (prefs.dcc_send_fillspaces)
1823 *file = '_';
1824 else
1825 havespaces = 1;
1827 file++;
1829 dcc->nick = strdup (to);
1830 if (prefs.autoopendccsendwindow)
1832 if (fe_dcc_open_send_win (TRUE)) /* already open? add */
1833 fe_dcc_add (dcc);
1834 } else
1835 fe_dcc_add (dcc);
1837 if (passive)
1839 dcc->pasvid = new_id();
1840 snprintf (outbuf, sizeof (outbuf), (havespaces) ?
1841 "DCC SEND \"%s\" 199 0 %"DCC_SFMT" %d" :
1842 "DCC SEND %s 199 0 %"DCC_SFMT" %d",
1843 file_part (dcc->file),
1844 dcc->size, dcc->pasvid);
1845 } else
1847 snprintf (outbuf, sizeof (outbuf), (havespaces) ?
1848 "DCC SEND \"%s\" %u %d %"DCC_SFMT :
1849 "DCC SEND %s %u %d %"DCC_SFMT,
1850 file_part (dcc->file), dcc->addr,
1851 dcc->port, dcc->size);
1853 sess->server->p_ctcp (sess->server, to, outbuf);
1855 EMIT_SIGNAL (XP_TE_DCCOFFER, sess, file_part (dcc->file),
1856 to, dcc->file, NULL, 0);
1857 } else
1859 dcc_close (dcc, 0, TRUE);
1861 return;
1864 PrintTextf (sess, _("Cannot access %s\n"), dcc->file);
1865 PrintTextf (sess, "%s %d: %s\n", _("Error"), errno, errorstring (errno));
1866 xit:
1867 g_free (file_fs);
1868 dcc_close (dcc, 0, TRUE);
1871 static struct DCC *
1872 find_dcc_from_id (int id, int type)
1874 struct DCC *dcc;
1875 GSList *list = dcc_list;
1876 while (list)
1878 dcc = (struct DCC *) list->data;
1879 if (dcc->pasvid == id &&
1880 dcc->dccstat == STAT_QUEUED && dcc->type == type)
1881 return dcc;
1882 list = list->next;
1884 return 0;
1887 static struct DCC *
1888 find_dcc_from_port (int port, int type)
1890 struct DCC *dcc;
1891 GSList *list = dcc_list;
1892 while (list)
1894 dcc = (struct DCC *) list->data;
1895 if (dcc->port == port &&
1896 dcc->dccstat == STAT_QUEUED && dcc->type == type)
1897 return dcc;
1898 list = list->next;
1900 return 0;
1903 struct DCC *
1904 find_dcc (char *nick, char *file, int type)
1906 GSList *list = dcc_list;
1907 struct DCC *dcc;
1908 while (list)
1910 dcc = (struct DCC *) list->data;
1911 if (nick == NULL || !rfc_casecmp (nick, dcc->nick))
1913 if (type == -1 || dcc->type == type)
1915 if (!file[0])
1916 return dcc;
1917 if (!strcasecmp (file, file_part (dcc->file)))
1918 return dcc;
1919 if (!strcasecmp (file, dcc->file))
1920 return dcc;
1923 list = list->next;
1925 return 0;
1928 /* called when we receive a NICK change from server */
1930 void
1931 dcc_change_nick (struct server *serv, char *oldnick, char *newnick)
1933 struct DCC *dcc;
1934 GSList *list = dcc_list;
1936 while (list)
1938 dcc = (struct DCC *) list->data;
1939 if (dcc->serv == serv)
1941 if (!serv->p_cmp (dcc->nick, oldnick))
1943 if (dcc->nick)
1944 free (dcc->nick);
1945 dcc->nick = strdup (newnick);
1948 list = list->next;
1952 /* is the destination file the same? new_dcc is not opened yet */
1954 static int
1955 is_same_file (struct DCC *dcc, struct DCC *new_dcc)
1957 struct stat st_a, st_b;
1959 /* if it's the same filename, must be same */
1960 if (strcmp (dcc->destfile, new_dcc->destfile) == 0)
1961 return TRUE;
1963 /* now handle case-insensitive Filesystems: HFS+, FAT */
1964 /* this fstat() shouldn't really fail */
1965 if ((dcc->fp == -1 ? stat (dcc->destfile_fs, &st_a) : fstat (dcc->fp, &st_a)) == -1)
1966 return FALSE;
1967 if (stat (new_dcc->destfile_fs, &st_b) == -1)
1968 return FALSE;
1970 /* same inode, same device, same file! */
1971 if (st_a.st_ino == st_b.st_ino &&
1972 st_a.st_dev == st_b.st_dev)
1973 return TRUE;
1975 return FALSE;
1978 static int
1979 is_resumable (struct DCC *dcc)
1981 dcc->resumable = 0;
1983 /* Check the file size */
1984 if (access (dcc->destfile_fs, W_OK) == 0)
1986 struct stat st;
1988 if (stat (dcc->destfile_fs, &st) != -1)
1990 if (st.st_size < dcc->size)
1992 dcc->resumable = st.st_size;
1993 dcc->pos = st.st_size;
1995 else
1996 dcc->resume_error = 2;
1997 } else
1999 dcc->resume_errno = errno;
2000 dcc->resume_error = 1;
2002 } else
2004 dcc->resume_errno = errno;
2005 dcc->resume_error = 1;
2008 /* Now verify that this DCC is not already in progress from someone else */
2010 if (dcc->resumable)
2012 GSList *list = dcc_list;
2013 struct DCC *d;
2014 while (list)
2016 d = list->data;
2017 if (d->type == TYPE_RECV && d->dccstat != STAT_ABORTED &&
2018 d->dccstat != STAT_DONE && d->dccstat != STAT_FAILED)
2020 if (d != dcc && is_same_file (d, dcc))
2022 dcc->resume_error = 3; /* dccgui.c uses it */
2023 dcc->resumable = 0;
2024 dcc->pos = 0;
2025 break;
2028 list = list->next;
2032 return dcc->resumable;
2035 void
2036 dcc_get (struct DCC *dcc)
2038 switch (dcc->dccstat)
2040 case STAT_QUEUED:
2041 if (dcc->type != TYPE_CHATSEND)
2043 if (dcc->type == TYPE_RECV && prefs.autoresume && dcc->resumable)
2045 dcc_resume (dcc);
2047 else
2049 dcc->resumable = 0;
2050 dcc->pos = 0;
2051 dcc_connect (dcc);
2054 break;
2055 case STAT_DONE:
2056 case STAT_FAILED:
2057 case STAT_ABORTED:
2058 dcc_close (dcc, 0, TRUE);
2059 break;
2063 /* for "Save As..." dialog */
2065 void
2066 dcc_get_with_destfile (struct DCC *dcc, char *file)
2068 g_free (dcc->destfile);
2069 dcc->destfile = g_strdup (file); /* utf-8 */
2071 /* get the local filesystem encoding */
2072 g_free (dcc->destfile_fs);
2073 dcc->destfile_fs = xchat_filename_from_utf8 (dcc->destfile, -1, 0, 0, 0);
2075 /* since destfile changed, must check resumability again */
2076 is_resumable (dcc);
2078 dcc_get (dcc);
2081 void
2082 dcc_get_nick (struct session *sess, char *nick)
2084 struct DCC *dcc;
2085 GSList *list = dcc_list;
2086 while (list)
2088 dcc = (struct DCC *) list->data;
2089 if (!sess->server->p_cmp (nick, dcc->nick))
2091 if (dcc->dccstat == STAT_QUEUED && dcc->type == TYPE_RECV)
2093 dcc->resumable = 0;
2094 dcc->pos = 0;
2095 dcc->ack = 0;
2096 dcc_connect (dcc);
2097 return;
2100 list = list->next;
2102 if (sess)
2103 EMIT_SIGNAL (XP_TE_DCCIVAL, sess, NULL, NULL, NULL, NULL, 0);
2106 static struct DCC *
2107 new_dcc (void)
2109 struct DCC *dcc = malloc (sizeof (struct DCC));
2110 if (!dcc)
2111 return 0;
2112 memset (dcc, 0, sizeof (struct DCC));
2113 dcc->sok = -1;
2114 dcc->fp = -1;
2115 dcc_list = g_slist_prepend (dcc_list, dcc);
2116 return (dcc);
2119 void
2120 dcc_chat (struct session *sess, char *nick, int passive)
2122 char outbuf[512];
2123 struct DCC *dcc;
2125 dcc = find_dcc (nick, "", TYPE_CHATSEND);
2126 if (dcc)
2128 switch (dcc->dccstat)
2130 case STAT_ACTIVE:
2131 case STAT_QUEUED:
2132 case STAT_CONNECTING:
2133 EMIT_SIGNAL (XP_TE_DCCCHATREOFFER, sess, nick, NULL, NULL, NULL, 0);
2134 return;
2135 case STAT_ABORTED:
2136 case STAT_FAILED:
2137 dcc_close (dcc, 0, TRUE);
2140 dcc = find_dcc (nick, "", TYPE_CHATRECV);
2141 if (dcc)
2143 switch (dcc->dccstat)
2145 case STAT_QUEUED:
2146 dcc_connect (dcc);
2147 break;
2148 case STAT_FAILED:
2149 case STAT_ABORTED:
2150 dcc_close (dcc, 0, TRUE);
2152 return;
2154 /* offer DCC CHAT */
2156 dcc = new_dcc ();
2157 if (!dcc)
2158 return;
2159 dcc->starttime = dcc->offertime = time (0);
2160 dcc->serv = sess->server;
2161 dcc->dccstat = STAT_QUEUED;
2162 dcc->type = TYPE_CHATSEND;
2163 dcc->nick = strdup (nick);
2164 if (passive || dcc_listen_init (dcc, sess))
2166 if (prefs.autoopendccchatwindow)
2168 if (fe_dcc_open_chat_win (TRUE)) /* already open? add only */
2169 fe_dcc_add (dcc);
2170 } else
2171 fe_dcc_add (dcc);
2173 if (passive)
2175 dcc->pasvid = new_id ();
2176 snprintf (outbuf, sizeof (outbuf), "DCC CHAT chat 199 %d %d",
2177 dcc->port, dcc->pasvid);
2178 } else
2180 snprintf (outbuf, sizeof (outbuf), "DCC CHAT chat %u %d",
2181 dcc->addr, dcc->port);
2183 dcc->serv->p_ctcp (dcc->serv, nick, outbuf);
2184 EMIT_SIGNAL (XP_TE_DCCCHATOFFERING, sess, nick, NULL, NULL, NULL, 0);
2185 } else
2187 dcc_close (dcc, 0, TRUE);
2191 static void
2192 dcc_malformed (struct session *sess, char *nick, char *data)
2194 EMIT_SIGNAL (XP_TE_MALFORMED, sess, nick, data, NULL, NULL, 0);
2198 dcc_resume (struct DCC *dcc)
2200 char tbuf[500];
2202 if (dcc->dccstat == STAT_QUEUED && dcc->resumable)
2204 dcc->resume_sent = 1;
2205 /* filename contains spaces? Quote them! */
2206 snprintf (tbuf, sizeof (tbuf) - 10, strchr (dcc->file, ' ') ?
2207 "DCC RESUME \"%s\" %d %"DCC_SFMT :
2208 "DCC RESUME %s %d %"DCC_SFMT,
2209 dcc->file, dcc->port, dcc->resumable);
2211 if (dcc->pasvid)
2212 sprintf (tbuf + strlen (tbuf), " %d", dcc->pasvid);
2214 dcc->serv->p_ctcp (dcc->serv, dcc->nick, tbuf);
2215 return 1;
2218 return 0;
2221 static void
2222 dcc_confirm_send (void *ud)
2224 struct DCC *dcc = (struct DCC *) ud;
2225 dcc_get (dcc);
2228 static void
2229 dcc_deny_send (void *ud)
2231 struct DCC *dcc = (struct DCC *) ud;
2232 dcc_abort (dcc->serv->front_session, dcc);
2235 static void
2236 dcc_confirm_chat (void *ud)
2238 struct DCC *dcc = (struct DCC *) ud;
2239 dcc_connect (dcc);
2242 static void
2243 dcc_deny_chat (void *ud)
2245 struct DCC *dcc = (struct DCC *) ud;
2246 dcc_abort (dcc->serv->front_session, dcc);
2249 static struct DCC *
2250 dcc_add_chat (session *sess, char *nick, int port, guint32 addr, int pasvid)
2252 struct DCC *dcc;
2254 dcc = new_dcc ();
2255 if (dcc)
2257 dcc->serv = sess->server;
2258 dcc->type = TYPE_CHATRECV;
2259 dcc->dccstat = STAT_QUEUED;
2260 dcc->addr = addr;
2261 dcc->port = port;
2262 dcc->pasvid = pasvid;
2263 dcc->nick = strdup (nick);
2264 dcc->starttime = time (0);
2266 EMIT_SIGNAL (XP_TE_DCCCHATOFFER, sess->server->front_session, nick,
2267 NULL, NULL, NULL, 0);
2269 if (prefs.autoopendccchatwindow)
2271 if (fe_dcc_open_chat_win (TRUE)) /* already open? add only */
2272 fe_dcc_add (dcc);
2273 } else
2274 fe_dcc_add (dcc);
2276 if (prefs.autodccchat == 1)
2277 dcc_connect (dcc);
2278 else if (prefs.autodccchat == 2)
2280 char buff[128];
2281 snprintf (buff, sizeof (buff), "%s is offering DCC Chat. Do you want to accept?", nick);
2282 fe_confirm (buff, dcc_confirm_chat, dcc_deny_chat, dcc);
2286 return dcc;
2289 static struct DCC *
2290 dcc_add_file (session *sess, char *file, DCC_SIZE size, int port, char *nick, guint32 addr, int pasvid)
2292 struct DCC *dcc;
2293 char tbuf[512];
2295 dcc = new_dcc ();
2296 if (dcc)
2298 dcc->file = strdup (file);
2300 dcc->destfile = g_malloc (strlen (prefs.dccdir) + strlen (nick) +
2301 strlen (file) + 4);
2303 strcpy (dcc->destfile, prefs.dccdir);
2304 if (prefs.dccdir[strlen (prefs.dccdir) - 1] != '/')
2305 strcat (dcc->destfile, "/");
2306 if (prefs.dccwithnick)
2308 strcat (dcc->destfile, nick);
2309 strcat (dcc->destfile, ".");
2311 strcat (dcc->destfile, file);
2313 /* get the local filesystem encoding */
2314 dcc->destfile_fs = xchat_filename_from_utf8 (dcc->destfile, -1, 0, 0, 0);
2316 dcc->resumable = 0;
2317 dcc->pos = 0;
2318 dcc->serv = sess->server;
2319 dcc->type = TYPE_RECV;
2320 dcc->dccstat = STAT_QUEUED;
2321 dcc->addr = addr;
2322 dcc->port = port;
2323 dcc->pasvid = pasvid;
2324 dcc->size = size;
2325 dcc->nick = strdup (nick);
2326 dcc->maxcps = prefs.dcc_max_get_cps;
2328 is_resumable (dcc);
2330 /* autodccsend is really autodccrecv.. right? */
2332 if (prefs.autodccsend == 1)
2334 dcc_get (dcc);
2336 else if (prefs.autodccsend == 2)
2338 snprintf (tbuf, sizeof (tbuf), _("%s is offering \"%s\". Do you want to accept?"), nick, file);
2339 fe_confirm (tbuf, dcc_confirm_send, dcc_deny_send, dcc);
2341 if (prefs.autoopendccrecvwindow)
2343 if (fe_dcc_open_recv_win (TRUE)) /* was already open? just add*/
2344 fe_dcc_add (dcc);
2345 } else
2346 fe_dcc_add (dcc);
2348 sprintf (tbuf, "%"DCC_SFMT, size);
2349 snprintf (tbuf + 24, 300, "%s:%d", net_ip (addr), port);
2350 EMIT_SIGNAL (XP_TE_DCCSENDOFFER, sess->server->front_session, nick,
2351 file, tbuf, tbuf + 24, 0);
2353 return dcc;
2356 void
2357 handle_dcc (struct session *sess, char *nick, char *word[],
2358 char *word_eol[])
2360 char tbuf[512];
2361 struct DCC *dcc;
2362 char *type = word[5];
2363 int port, pasvid = 0;
2364 guint32 addr;
2365 DCC_SIZE size;
2366 int psend = 0;
2368 if (!strcasecmp (type, "CHAT"))
2370 port = atoi (word[8]);
2371 addr = strtoul (word[7], NULL, 10);
2373 if (port == 0)
2374 pasvid = atoi (word[9]);
2375 else if (word[9][0] != 0)
2377 pasvid = atoi (word[9]);
2378 psend = 1;
2381 if (!addr /*|| (port < 1024 && port != 0)*/
2382 || port > 0xffff || (port == 0 && pasvid == 0))
2384 dcc_malformed (sess, nick, word_eol[4] + 2);
2385 return;
2388 if (psend)
2390 dcc = find_dcc_from_id (pasvid, TYPE_CHATSEND);
2391 if (dcc)
2393 dcc->addr = addr;
2394 dcc->port = port;
2395 dcc_connect (dcc);
2396 } else
2398 dcc_malformed (sess, nick, word_eol[4] + 2);
2400 return;
2403 dcc = find_dcc (nick, "", TYPE_CHATSEND);
2404 if (dcc)
2405 dcc_close (dcc, 0, TRUE);
2407 dcc = find_dcc (nick, "", TYPE_CHATRECV);
2408 if (dcc)
2409 dcc_close (dcc, 0, TRUE);
2411 dcc_add_chat (sess, nick, port, addr, pasvid);
2412 return;
2415 if (!strcasecmp (type, "Resume"))
2417 port = atoi (word[7]);
2419 if (port == 0)
2420 { /* PASSIVE */
2421 pasvid = atoi(word[9]);
2422 dcc = find_dcc_from_id(pasvid, TYPE_SEND);
2423 } else
2425 dcc = find_dcc_from_port (port, TYPE_SEND);
2427 if (!dcc)
2428 dcc = find_dcc (nick, word[6], TYPE_SEND);
2429 if (dcc)
2431 size = BIG_STR_TO_INT (word[8]);
2432 dcc->resumable = size;
2433 if (dcc->resumable < dcc->size)
2435 dcc->pos = dcc->resumable;
2436 dcc->ack = dcc->resumable;
2437 lseek (dcc->fp, dcc->pos, SEEK_SET);
2439 /* Checking if dcc is passive and if filename contains spaces */
2440 if (dcc->pasvid)
2441 snprintf (tbuf, sizeof (tbuf), strchr (file_part (dcc->file), ' ') ?
2442 "DCC ACCEPT \"%s\" %d %"DCC_SFMT" %d" :
2443 "DCC ACCEPT %s %d %"DCC_SFMT" %d",
2444 file_part (dcc->file), port, dcc->resumable, dcc->pasvid);
2445 else
2446 snprintf (tbuf, sizeof (tbuf), strchr (file_part (dcc->file), ' ') ?
2447 "DCC ACCEPT \"%s\" %d %"DCC_SFMT :
2448 "DCC ACCEPT %s %d %"DCC_SFMT,
2449 file_part (dcc->file), port, dcc->resumable);
2451 dcc->serv->p_ctcp (dcc->serv, dcc->nick, tbuf);
2453 sprintf (tbuf, "%"DCC_SFMT, dcc->pos);
2454 EMIT_SIGNAL (XP_TE_DCCRESUMEREQUEST, sess, nick,
2455 file_part (dcc->file), tbuf, NULL, 0);
2457 return;
2459 if (!strcasecmp (type, "Accept"))
2461 port = atoi (word[7]);
2462 dcc = find_dcc_from_port (port, TYPE_RECV);
2463 if (dcc && dcc->dccstat == STAT_QUEUED)
2465 dcc_connect (dcc);
2467 return;
2469 if (!strcasecmp (type, "SEND"))
2471 char *file = file_part (word[6]);
2473 port = atoi (word[8]);
2474 addr = strtoul (word[7], NULL, 10);
2475 size = BIG_STR_TO_INT (word[9]);
2477 if (port == 0) /* Passive dcc requested */
2478 pasvid = atoi (word[10]);
2479 else if (word[10][0] != 0)
2481 /* Requesting passive dcc.
2482 * Destination user of an active dcc is giving his
2483 * TRUE address/port/pasvid data.
2484 * This information will be used later to
2485 * establish the connection to the user.
2486 * We can recognize this type of dcc using word[10]
2487 * because this field is always null (no pasvid)
2488 * in normal dcc sends.
2490 pasvid = atoi (word[10]);
2491 psend = 1;
2495 if (!addr || !size /*|| (port < 1024 && port != 0)*/
2496 || port > 0xffff || (port == 0 && pasvid == 0))
2498 dcc_malformed (sess, nick, word_eol[4] + 2);
2499 return;
2502 if (psend)
2504 /* Third Step of Passive send.
2505 * Connecting to the destination and finally
2506 * sending file.
2508 dcc = find_dcc_from_id (pasvid, TYPE_SEND);
2509 if (dcc)
2511 dcc->addr = addr;
2512 dcc->port = port;
2513 dcc_connect (dcc);
2514 } else
2516 dcc_malformed (sess, nick, word_eol[4] + 2);
2518 return;
2521 dcc_add_file (sess, file, size, port, nick, addr, pasvid);
2523 } else
2525 EMIT_SIGNAL (XP_TE_DCCGENERICOFFER, sess->server->front_session,
2526 word_eol[4] + 2, nick, NULL, NULL, 0);
2530 void
2531 dcc_show_list (struct session *sess)
2533 int i = 0;
2534 struct DCC *dcc;
2535 GSList *list = dcc_list;
2537 EMIT_SIGNAL (XP_TE_DCCHEAD, sess, NULL, NULL, NULL, NULL, 0);
2538 while (list)
2540 dcc = (struct DCC *) list->data;
2541 i++;
2542 PrintTextf (sess, " %s %-10.10s %-7.7s %-7"DCC_SFMT" %-7"DCC_SFMT" %s\n",
2543 dcctypes[dcc->type], dcc->nick,
2544 _(dccstat[dcc->dccstat].name), dcc->size, dcc->pos,
2545 file_part (dcc->file));
2546 list = list->next;
2548 if (!i)
2549 PrintText (sess, _("No active DCCs\n"));