1 /* X-Chat
2 * Copyright (C) 1998-2006 Peter Zelezny.
3 * Copyright (C) 2006 Damjan Jovanovic
4 *
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.
9 *
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.
14 *
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 *
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
21 *
22 * 2001-03-08 Added support for getting "dcc_ip" config parameter.
23 * Jim Seymour (jseymour@LinxNet.com)
24 */
25
26 /* Required to make lseek use off64_t, but doesn't work on Windows */
27 #define _FILE_OFFSET_BITS 64
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <time.h>
33 #include <errno.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36
37 #define WANTSOCKET
38 #define WANTARPA
39 #define WANTDNS
40 #include "inet.h"
41
42 #ifdef WIN32
43 #include <windows.h>
44 #include <io.h>
45 #else
46 #include <unistd.h>
47 #endif
48
49 #include "hexchat.h"
50 #include "util.h"
51 #include "fe.h"
52 #include "outbound.h"
53 #include "inbound.h"
54 #include "network.h"
55 #include "plugin.h"
56 #include "server.h"
57 #include "text.h"
58 #include "url.h"
59 #include "hexchatc.h"
60
61 /* Setting _FILE_OFFSET_BITS to 64 doesn't change lseek to use off64_t on Windows, so override lseek to the version that does */
62 #if defined(WIN32) && (!defined(__MINGW32__) && !defined(__MINGW64__))
63 #define lseek _lseeki64
64 #endif
65
66 /* interval timer to detect timeouts */
67 static int timeout_timer = 0;
68
69 static char *dcctypes[] = { "SEND", "RECV", "CHAT", "CHAT" };
70
71 struct dccstat_info dccstat[] = {
72 {N_("Waiting"), 1 /*black */ },
73 {N_("Active"), 12 /*cyan */ },
74 {N_("Failed"), 4 /*red */ },
75 {N_("Done"), 3 /*green */ },
76 {N_("Connect"), 1 /*black */ },
77 {N_("Aborted"), 4 /*red */ },
78 };
79
80 static int dcc_global_throttle; /* 0x1 = sends, 0x2 = gets */
81 static gint64 dcc_sendcpssum, dcc_getcpssum;
82
83 static struct DCC *new_dcc (void);
84 static void dcc_close (struct DCC *dcc, enum dcc_state dccstat, int destroy);
85 static gboolean dcc_send_data (GIOChannel *, GIOCondition, struct DCC *);
86 static gboolean dcc_read (GIOChannel *, GIOCondition, struct DCC *);
87 static gboolean dcc_read_ack (GIOChannel *source, GIOCondition condition, struct DCC *dcc);
88 static int dcc_check_timeouts (void);
89
new_id(void)90 static int new_id(void)
91 {
92 static int id = 0;
93 if (id == 0)
94 {
95 /* start the first ID at a random number for pseudo security */
96 /* 1 - 255 */
97 id = RAND_INT(255) + 1;
98 /* ignore overflows, since it can go to 2 billion */
99 }
100 return id++;
101 }
102
103 static double
timeval_diff(GTimeVal * greater,GTimeVal * less)104 timeval_diff (GTimeVal *greater,
105 GTimeVal *less)
106 {
107 long usecdiff;
108 double result;
109
110 result = greater->tv_sec - less->tv_sec;
111 usecdiff = (long) greater->tv_usec - less->tv_usec;
112 result += (double) usecdiff / 1000000;
113
114 return result;
115 }
116
117 static void
dcc_unthrottle(struct DCC * dcc)118 dcc_unthrottle (struct DCC *dcc)
119 {
120 /* don't unthrottle here, but delegate to funcs */
121 if (dcc->type == TYPE_RECV)
122 dcc_read (NULL, 0, dcc);
123 else
124 dcc_send_data (NULL, 0, dcc);
125 }
126
127 static void
dcc_calc_cps(struct DCC * dcc)128 dcc_calc_cps (struct DCC *dcc)
129 {
130 GTimeVal now;
131 gint64 oldcps;
132 double timediff, startdiff;
133 int glob_throttle_bit, wasthrottled;
134 gint64 *cpssum;
135 int glob_limit;
136 goffset pos, posdiff;
137
138 g_get_current_time (&now);
139
140 /* the pos we use for sends is an average
141 between pos and ack */
142 if (dcc->type == TYPE_SEND)
143 {
144 /* carefull to avoid 32bit overflow */
145 pos = dcc->pos - ((dcc->pos - dcc->ack) / 2);
146 glob_throttle_bit = 0x1;
147 cpssum = &dcc_sendcpssum;
148 glob_limit = prefs.hex_dcc_global_max_send_cps;
149 }
150 else
151 {
152 pos = dcc->pos;
153 glob_throttle_bit = 0x2;
154 cpssum = &dcc_getcpssum;
155 glob_limit = prefs.hex_dcc_global_max_get_cps;
156 }
157
158 if (!dcc->firstcpstv.tv_sec && !dcc->firstcpstv.tv_usec)
159 dcc->firstcpstv = now;
160 else
161 {
162 startdiff = timeval_diff (&now, &dcc->firstcpstv);
163 if (startdiff < 1)
164 startdiff = 1;
165 else if (startdiff > CPS_AVG_WINDOW)
166 startdiff = CPS_AVG_WINDOW;
167
168 timediff = timeval_diff (&now, &dcc->lastcpstv);
169 if (timediff > startdiff)
170 timediff = startdiff = 1;
171
172 posdiff = pos - dcc->lastcpspos;
173 oldcps = dcc->cps;
174 dcc->cps = (gint64) ((posdiff / timediff) * (timediff / startdiff) + dcc->cps * (1.0 - (timediff / startdiff)));
175
176 *cpssum += dcc->cps - oldcps;
177 }
178
179 dcc->lastcpspos = pos;
180 dcc->lastcpstv = now;
181
182 /* now check cps against set limits... */
183 wasthrottled = dcc->throttled;
184
185 /* check global limits first */
186 dcc->throttled &= ~0x2;
187 if (glob_limit > 0 && *cpssum >= glob_limit)
188 {
189 dcc_global_throttle |= glob_throttle_bit;
190 if (dcc->maxcps >= 0)
191 dcc->throttled |= 0x2;
192 }
193 else
194 dcc_global_throttle &= ~glob_throttle_bit;
195
196 /* now check per-connection limit */
197 if (dcc->maxcps > 0 && dcc->cps > dcc->maxcps)
198 dcc->throttled |= 0x1;
199 else
200 dcc->throttled &= ~0x1;
201
202 /* take action */
203 if (wasthrottled && !dcc->throttled)
204 dcc_unthrottle (dcc);
205 }
206
207 static void
dcc_remove_from_sum(struct DCC * dcc)208 dcc_remove_from_sum (struct DCC *dcc)
209 {
210 if (dcc->dccstat != STAT_ACTIVE)
211 return;
212 if (dcc->type == TYPE_SEND)
213 dcc_sendcpssum -= dcc->cps;
214 else if (dcc->type == TYPE_RECV)
215 dcc_getcpssum -= dcc->cps;
216 }
217
218 gboolean
is_dcc(struct DCC * dcc)219 is_dcc (struct DCC *dcc)
220 {
221 GSList *list = dcc_list;
222 while (list)
223 {
224 if (list->data == dcc)
225 return TRUE;
226 list = list->next;
227 }
228 return FALSE;
229 }
230
231 gboolean
is_dcc_completed(struct DCC * dcc)232 is_dcc_completed (struct DCC *dcc)
233 {
234 if (dcc != NULL)
235 return (dcc->dccstat == STAT_FAILED || dcc->dccstat == STAT_DONE || dcc->dccstat == STAT_ABORTED);
236
237 return FALSE;
238 }
239
240 /* this is called by timeout_timer every 1 second. */
241
242 int
dcc_check_timeouts(void)243 dcc_check_timeouts (void)
244 {
245 struct DCC *dcc;
246 time_t tim = time (0);
247 GSList *next, *list = dcc_list;
248
249 while (list)
250 {
251 dcc = (struct DCC *) list->data;
252 next = list->next;
253
254 switch (dcc->dccstat)
255 {
256 case STAT_ACTIVE:
257 dcc_calc_cps (dcc);
258 fe_dcc_update (dcc);
259
260 if (dcc->type == TYPE_SEND || dcc->type == TYPE_RECV)
261 {
262 if (prefs.hex_dcc_stall_timeout > 0)
263 {
264 if (!dcc->throttled
265 && tim - dcc->lasttime > prefs.hex_dcc_stall_timeout)
266 {
267 EMIT_SIGNAL (XP_TE_DCCSTALL, dcc->serv->front_session,
268 dcctypes[dcc->type],
269 file_part (dcc->file), dcc->nick, NULL, 0);
270 dcc_close (dcc, STAT_ABORTED, FALSE);
271 }
272 }
273 }
274 break;
275 case STAT_QUEUED:
276 if (dcc->type == TYPE_SEND || dcc->type == TYPE_CHATSEND)
277 {
278 if (tim - dcc->offertime > prefs.hex_dcc_timeout)
279 {
280 if (prefs.hex_dcc_timeout > 0)
281 {
282 EMIT_SIGNAL (XP_TE_DCCTOUT, dcc->serv->front_session,
283 dcctypes[dcc->type],
284 file_part (dcc->file), dcc->nick, NULL, 0);
285 dcc_close (dcc, STAT_ABORTED, FALSE);
286 }
287 }
288 }
289 break;
290 case STAT_DONE:
291 case STAT_FAILED:
292 case STAT_ABORTED:
293 if (prefs.hex_dcc_remove)
294 dcc_close (dcc, 0, TRUE);
295 break;
296 default:
297 break;
298 }
299 list = next;
300 }
301 return 1;
302 }
303
304 static int
dcc_lookup_proxy(char * host,struct sockaddr_in * addr)305 dcc_lookup_proxy (char *host, struct sockaddr_in *addr)
306 {
307 struct hostent *h;
308 static char *cache_host = NULL;
309 static guint32 cache_addr;
310
311 /* too lazy to thread this, so we cache results */
312 if (cache_host)
313 {
314 if (strcmp (host, cache_host) == 0)
315 {
316 memcpy (&addr->sin_addr, &cache_addr, 4);
317 return TRUE;
318 }
319 g_free (cache_host);
320 cache_host = NULL;
321 }
322
323 h = gethostbyname (host);
324 if (h != NULL && h->h_length == 4 && h->h_addr_list[0] != NULL)
325 {
326 memcpy (&addr->sin_addr, h->h_addr, 4);
327 memcpy (&cache_addr, h->h_addr, 4);
328 cache_host = g_strdup (host);
329 /* cppcheck-suppress memleak */
330 return TRUE;
331 }
332
333 return FALSE;
334 }
335
336 #define DCC_USE_PROXY() (prefs.hex_net_proxy_host[0] && prefs.hex_net_proxy_type>0 && prefs.hex_net_proxy_type<5 && prefs.hex_net_proxy_use!=1)
337
338 static int
dcc_connect_sok(struct DCC * dcc)339 dcc_connect_sok (struct DCC *dcc)
340 {
341 int sok;
342 struct sockaddr_in addr;
343
344 sok = socket (AF_INET, SOCK_STREAM, 0);
345 if (sok == -1)
346 return -1;
347
348 memset (&addr, 0, sizeof (addr));
349 addr.sin_family = AF_INET;
350 if (DCC_USE_PROXY ())
351 {
352 if (!dcc_lookup_proxy (prefs.hex_net_proxy_host, &addr))
353 {
354 closesocket (sok);
355 return -1;
356 }
357 addr.sin_port = htons (prefs.hex_net_proxy_port);
358 }
359 else
360 {
361 addr.sin_port = htons (dcc->port);
362 addr.sin_addr.s_addr = htonl (dcc->addr);
363 }
364
365 set_nonblocking (sok);
366 connect (sok, (struct sockaddr *) &addr, sizeof (addr));
367
368 return sok;
369 }
370
371 static void
dcc_close(struct DCC * dcc,enum dcc_state dccstat,int destroy)372 dcc_close (struct DCC *dcc, enum dcc_state dccstat, int destroy)
373 {
374 if (dcc->wiotag)
375 {
376 fe_input_remove (dcc->wiotag);
377 dcc->wiotag = 0;
378 }
379
380 if (dcc->iotag)
381 {
382 fe_input_remove (dcc->iotag);
383 dcc->iotag = 0;
384 }
385
386 if (dcc->sok != -1)
387 {
388 closesocket (dcc->sok);
389 dcc->sok = -1;
390 }
391
392 dcc_remove_from_sum (dcc);
393
394 if (dcc->fp != -1)
395 {
396 close (dcc->fp);
397 dcc->fp = -1;
398
399 if(dccstat == STAT_DONE)
400 {
401 /* if we just completed a dcc receive, move the */
402 /* completed file to the completed directory */
403 if(dcc->type == TYPE_RECV)
404 {
405 /* mgl: change this to handle the case where dccwithnick is set */
406 move_file (prefs.hex_dcc_dir, prefs.hex_dcc_completed_dir,
407 file_part (dcc->destfile), prefs.hex_dcc_permissions);
408 }
409
410 }
411 }
412
413 dcc->dccstat = dccstat;
414 if (dcc->dccchat)
415 {
416 g_free (dcc->dccchat);
417 dcc->dccchat = NULL;
418 }
419
420 if (destroy)
421 {
422 dcc_list = g_slist_remove (dcc_list, dcc);
423 fe_dcc_remove (dcc);
424 g_free (dcc->proxy);
425 g_free (dcc->file);
426 g_free (dcc->destfile);
427 g_free (dcc->nick);
428 g_free (dcc);
429 if (dcc_list == NULL && timeout_timer != 0)
430 {
431 fe_timeout_remove (timeout_timer);
432 timeout_timer = 0;
433 }
434 return;
435 }
436
437 fe_dcc_update (dcc);
438 }
439
440 void
dcc_abort(session * sess,struct DCC * dcc)441 dcc_abort (session *sess, struct DCC *dcc)
442 {
443 if (dcc)
444 {
445 switch (dcc->dccstat)
446 {
447 case STAT_QUEUED:
448 case STAT_CONNECTING:
449 case STAT_ACTIVE:
450 dcc_close (dcc, STAT_ABORTED, FALSE);
451 switch (dcc->type)
452 {
453 case TYPE_CHATSEND:
454 case TYPE_CHATRECV:
455 EMIT_SIGNAL (XP_TE_DCCCHATABORT, sess, dcc->nick, NULL, NULL,
456 NULL, 0);
457 break;
458 case TYPE_SEND:
459 EMIT_SIGNAL (XP_TE_DCCSENDABORT, sess, dcc->nick,
460 file_part (dcc->file), NULL, NULL, 0);
461 break;
462 case TYPE_RECV:
463 EMIT_SIGNAL (XP_TE_DCCRECVABORT, sess, dcc->nick,
464 dcc->file, NULL, NULL, 0);
465 }
466 break;
467 default:
468 dcc_close (dcc, 0, TRUE);
469 }
470 }
471 }
472
473 void
dcc_notify_kill(struct server * serv)474 dcc_notify_kill (struct server *serv)
475 {
476 struct server *replaceserv = 0;
477 struct DCC *dcc;
478 GSList *list = dcc_list;
479 if (serv_list)
480 replaceserv = (struct server *) serv_list->data;
481 while (list)
482 {
483 dcc = (struct DCC *) list->data;
484 if (dcc->serv == serv)
485 dcc->serv = replaceserv;
486 list = list->next;
487 }
488 }
489
490 struct DCC *
dcc_write_chat(char * nick,char * text)491 dcc_write_chat (char *nick, char *text)
492 {
493 struct DCC *dcc;
494 int len;
495
496 dcc = find_dcc (nick, "", TYPE_CHATRECV);
497 if (!dcc)
498 dcc = find_dcc (nick, "", TYPE_CHATSEND);
499 if (dcc && dcc->dccstat == STAT_ACTIVE)
500 {
501 len = strlen (text);
502 tcp_send_real (NULL, dcc->sok, dcc->serv->write_converter, text, len);
503 send (dcc->sok, "\n", 1, 0);
504 dcc->size += len;
505 fe_dcc_update (dcc);
506 return dcc;
507 }
508 return NULL;
509 }
510
511 /* returns: 0 - ok
512 1 - the dcc is closed! */
513
514 static int
dcc_chat_line(struct DCC * dcc,char * line)515 dcc_chat_line (struct DCC *dcc, char *line)
516 {
517 session *sess;
518 char *word[PDIWORDS];
519 char *po;
520 int ret, i;
521 char portbuf[32];
522 message_tags_data no_tags = MESSAGE_TAGS_DATA_INIT;
523
524 line = text_convert_invalid (line, -1, dcc->serv->read_converter, unicode_fallback_string, NULL);
525
526 sess = find_dialog (dcc->serv, dcc->nick);
527 if (!sess)
528 sess = dcc->serv->front_session;
529
530 sprintf (portbuf, "%d", dcc->port);
531
532 word[0] = "DCC Chat Text";
533 word[1] = net_ip (dcc->addr);
534 word[2] = portbuf;
535 word[3] = dcc->nick;
536 word[4] = line;
537 for (i = 5; i < PDIWORDS; i++)
538 word[i] = "\000";
539
540 ret = plugin_emit_print (sess, word, 0);
541
542 /* did the plugin close it? */
543 if (!g_slist_find (dcc_list, dcc))
544 {
545 g_free (line);
546 return 1;
547 }
548
549 /* did the plugin eat the event? */
550 if (ret)
551 {
552 g_free (line);
553 return 0;
554 }
555
556 url_check_line (line);
557
558 if (line[0] == 1 && !g_ascii_strncasecmp (line + 1, "ACTION", 6))
559 {
560 po = strchr (line + 8, '\001');
561 if (po)
562 po[0] = 0;
563 inbound_action (sess, dcc->serv->nick, dcc->nick, "", line + 8, FALSE,
564 FALSE, &no_tags);
565 } else
566 {
567 inbound_privmsg (dcc->serv, dcc->nick, "", line, FALSE, &no_tags);
568 }
569 g_free (line);
570 return 0;
571 }
572
573 static gboolean
dcc_read_chat(GIOChannel * source,GIOCondition condition,struct DCC * dcc)574 dcc_read_chat (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
575 {
576 int i, len, dead;
577 char portbuf[32];
578 char lbuf[2050];
579
580 while (1)
581 {
582 if (dcc->throttled)
583 {
584 fe_input_remove (dcc->iotag);
585 dcc->iotag = 0;
586 return FALSE;
587 }
588
589 if (!dcc->iotag)
590 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX, dcc_read_chat, dcc);
591
592 len = recv (dcc->sok, lbuf, sizeof (lbuf) - 2, 0);
593 if (len < 1)
594 {
595 if (len < 0)
596 {
597 if (would_block ())
598 return TRUE;
599 }
600 sprintf (portbuf, "%d", dcc->port);
601 EMIT_SIGNAL (XP_TE_DCCCHATF, dcc->serv->front_session, dcc->nick,
602 net_ip (dcc->addr), portbuf,
603 errorstring ((len < 0) ? sock_error () : 0), 0);
604 dcc_close (dcc, STAT_FAILED, FALSE);
605 return TRUE;
606 }
607 i = 0;
608 lbuf[len] = 0;
609 while (i < len)
610 {
611 switch (lbuf[i])
612 {
613 case '\r':
614 break;
615 case '\n':
616 dcc->dccchat->linebuf[dcc->dccchat->pos] = 0;
617 dead = dcc_chat_line (dcc, dcc->dccchat->linebuf);
618
619 if (dead || !dcc->dccchat) /* the dcc has been closed, don't use (DCC *)! */
620 return TRUE;
621
622 dcc->pos += dcc->dccchat->pos;
623 dcc->dccchat->pos = 0;
624 fe_dcc_update (dcc);
625 break;
626 default:
627 dcc->dccchat->linebuf[dcc->dccchat->pos] = lbuf[i];
628 if (dcc->dccchat->pos < (sizeof (dcc->dccchat->linebuf) - 1))
629 dcc->dccchat->pos++;
630 }
631 i++;
632 }
633 }
634 }
635
636 static void
dcc_calc_average_cps(struct DCC * dcc)637 dcc_calc_average_cps (struct DCC *dcc)
638 {
639 time_t sec;
640
641 sec = time (0) - dcc->starttime;
642 if (sec < 1)
643 sec = 1;
644 if (dcc->type == TYPE_SEND)
645 dcc->cps = (dcc->ack - dcc->resumable) / sec;
646 else
647 dcc->cps = (dcc->pos - dcc->resumable) / sec;
648 }
649
650 static void
dcc_send_ack(struct DCC * dcc)651 dcc_send_ack (struct DCC *dcc)
652 {
653 /* send in 32-bit big endian */
654 guint32 pos = htonl (dcc->pos & 0xffffffff);
655 send (dcc->sok, (char *) &pos, 4, 0);
656 }
657
658 static gboolean
dcc_read(GIOChannel * source,GIOCondition condition,struct DCC * dcc)659 dcc_read (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
660 {
661 char *old;
662 char buf[4096];
663 int n;
664 gboolean need_ack = FALSE;
665
666 if (dcc->fp == -1)
667 {
668
669 /* try to create the download dir (even if it exists, no harm) */
670 g_mkdir (prefs.hex_dcc_dir, 0700);
671
672 if (dcc->resumable)
673 {
674 gchar *filename_fs = g_filename_from_utf8(dcc->destfile, -1, NULL, NULL, NULL);
675 dcc->fp = g_open(dcc->destfile, O_WRONLY | O_APPEND | OFLAGS, 0);
676 g_free (filename_fs);
677
678 dcc->pos = dcc->resumable;
679 dcc->ack = dcc->resumable;
680 }
681 else
682 {
683 gchar *filename_fs;
684
685 if (g_access (dcc->destfile, F_OK) == 0)
686 {
687 n = 0;
688 do
689 {
690 n++;
691 g_snprintf (buf, sizeof (buf), "%s.%d", dcc->destfile, n);
692 }
693 while (g_access (buf, F_OK) == 0);
694
695 old = dcc->destfile;
696 dcc->destfile = g_strdup (buf);
697
698 EMIT_SIGNAL (XP_TE_DCCRENAME, dcc->serv->front_session,
699 old, dcc->destfile, NULL, NULL, 0);
700 g_free (old);
701 }
702
703 filename_fs = g_filename_from_utf8 (dcc->destfile, -1, NULL, NULL, NULL);
704 dcc->fp = g_open (filename_fs, OFLAGS | O_TRUNC | O_WRONLY | O_CREAT, prefs.hex_dcc_permissions);
705 g_free (filename_fs);
706 }
707 }
708 if (dcc->fp == -1)
709 {
710 /* the last executed function is open(), errno should be valid */
711 EMIT_SIGNAL (XP_TE_DCCFILEERR, dcc->serv->front_session, dcc->destfile,
712 errorstring (errno), NULL, NULL, 0);
713 dcc_close (dcc, STAT_FAILED, FALSE);
714 return TRUE;
715 }
716 while (1)
717 {
718 if (dcc->throttled)
719 {
720 if (need_ack)
721 dcc_send_ack (dcc);
722
723 fe_input_remove (dcc->iotag);
724 dcc->iotag = 0;
725 return FALSE;
726 }
727
728 if (!dcc->iotag)
729 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX, dcc_read, dcc);
730
731 n = recv (dcc->sok, buf, sizeof (buf), 0);
732 if (n < 1)
733 {
734 if (n < 0)
735 {
736 if (would_block ())
737 {
738 if (need_ack)
739 dcc_send_ack (dcc);
740 return TRUE;
741 }
742 }
743 EMIT_SIGNAL (XP_TE_DCCRECVERR, dcc->serv->front_session, dcc->file,
744 dcc->destfile, dcc->nick,
745 errorstring ((n < 0) ? sock_error () : 0), 0);
746 /* send ack here? but the socket is dead */
747 /*if (need_ack)
748 dcc_send_ack (dcc);*/
749 dcc_close (dcc, STAT_FAILED, FALSE);
750 return TRUE;
751 }
752
753 if (write (dcc->fp, buf, n) == -1) /* could be out of hdd space */
754 {
755 EMIT_SIGNAL (XP_TE_DCCRECVERR, dcc->serv->front_session, dcc->file,
756 dcc->destfile, dcc->nick, errorstring (errno), 0);
757 if (need_ack)
758 dcc_send_ack (dcc);
759 dcc_close (dcc, STAT_FAILED, FALSE);
760 return TRUE;
761 }
762
763 dcc->lasttime = time (0);
764 dcc->pos += n;
765 need_ack = TRUE; /* send ack when we're done recv()ing */
766
767 if (dcc->pos >= dcc->size)
768 {
769 dcc_send_ack (dcc);
770 dcc_close (dcc, STAT_DONE, FALSE);
771 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 */
772 /* cppcheck-suppress deallocuse */
773 sprintf (buf, "%" G_GINT64_FORMAT, dcc->cps);
774 EMIT_SIGNAL (XP_TE_DCCRECVCOMP, dcc->serv->front_session,
775 dcc->file, dcc->destfile, dcc->nick, buf, 0);
776 return TRUE;
777 }
778 }
779 }
780
781 static void
dcc_open_query(server * serv,char * nick)782 dcc_open_query (server *serv, char *nick)
783 {
784 if (prefs.hex_gui_autoopen_dialog)
785 open_query (serv, nick, FALSE);
786 }
787
788 static gboolean
dcc_did_connect(GIOChannel * source,GIOCondition condition,struct DCC * dcc)789 dcc_did_connect (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
790 {
791 int er;
792
793 #ifdef WIN32
794 if (condition & G_IO_ERR)
795 {
796 int len;
797
798 /* find the last errno for this socket */
799 len = sizeof (er);
800 getsockopt (dcc->sok, SOL_SOCKET, SO_ERROR, (char *)&er, &len);
801 EMIT_SIGNAL (XP_TE_DCCCONFAIL, dcc->serv->front_session,
802 dcctypes[dcc->type], dcc->nick, errorstring (er),
803 NULL, 0);
804 dcc->dccstat = STAT_FAILED;
805 fe_dcc_update (dcc);
806 return FALSE;
807 }
808
809 #else
810 struct sockaddr_in addr;
811
812 memset (&addr, 0, sizeof (addr));
813 addr.sin_port = htons (dcc->port);
814 addr.sin_family = AF_INET;
815 addr.sin_addr.s_addr = htonl (dcc->addr);
816
817 /* check if it's already connected; This always fails on winXP */
818 if (connect (dcc->sok, (struct sockaddr *) &addr, sizeof (addr)) != 0)
819 {
820 er = sock_error ();
821 if (er != EISCONN)
822 {
823 EMIT_SIGNAL (XP_TE_DCCCONFAIL, dcc->serv->front_session,
824 dcctypes[dcc->type], dcc->nick, errorstring (er),
825 NULL, 0);
826 dcc->dccstat = STAT_FAILED;
827 fe_dcc_update (dcc);
828 return FALSE;
829 }
830 }
831 #endif
832
833 return TRUE;
834 }
835
836 static gboolean
dcc_connect_finished(GIOChannel * source,GIOCondition condition,struct DCC * dcc)837 dcc_connect_finished (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
838 {
839 char host[128];
840
841 if (dcc->iotag)
842 {
843 fe_input_remove (dcc->iotag);
844 dcc->iotag = 0;
845 }
846
847 if (!dcc_did_connect (source, condition, dcc))
848 return TRUE;
849
850 dcc->dccstat = STAT_ACTIVE;
851 g_snprintf (host, sizeof host, "%s:%d", net_ip (dcc->addr), dcc->port);
852
853 switch (dcc->type)
854 {
855 case TYPE_RECV:
856 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX, dcc_read, dcc);
857 EMIT_SIGNAL (XP_TE_DCCCONRECV, dcc->serv->front_session,
858 dcc->nick, host, dcc->file, NULL, 0);
859 break;
860 case TYPE_SEND:
861 /* passive send */
862 dcc->fastsend = prefs.hex_dcc_fast_send;
863 if (dcc->fastsend)
864 dcc->wiotag = fe_input_add (dcc->sok, FIA_WRITE, dcc_send_data, dcc);
865 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX, dcc_read_ack, dcc);
866 dcc_send_data (NULL, 0, (gpointer)dcc);
867 EMIT_SIGNAL (XP_TE_DCCCONSEND, dcc->serv->front_session,
868 dcc->nick, host, dcc->file, NULL, 0);
869 break;
870 case TYPE_CHATSEND: /* pchat */
871 dcc_open_query (dcc->serv, dcc->nick);
872 case TYPE_CHATRECV: /* normal chat */
873 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX, dcc_read_chat, dcc);
874 dcc->dccchat = g_new0 (struct dcc_chat, 1);
875 EMIT_SIGNAL (XP_TE_DCCCONCHAT, dcc->serv->front_session,
876 dcc->nick, host, NULL, NULL, 0);
877 break;
878 }
879 dcc->starttime = time (0);
880 dcc->lasttime = dcc->starttime;
881 fe_dcc_update (dcc);
882
883 return TRUE;
884 }
885
886 static gboolean
read_proxy(struct DCC * dcc)887 read_proxy (struct DCC *dcc)
888 {
889 struct proxy_state *proxy = dcc->proxy;
890 while (proxy->bufferused < proxy->buffersize)
891 {
892 int ret = recv (dcc->sok, &proxy->buffer[proxy->bufferused],
893 proxy->buffersize - proxy->bufferused, 0);
894 if (ret > 0)
895 proxy->bufferused += ret;
896 else
897 {
898 if (would_block ())
899 return FALSE;
900 else
901 {
902 dcc->dccstat = STAT_FAILED;
903 fe_dcc_update (dcc);
904 if (dcc->iotag)
905 {
906 fe_input_remove (dcc->iotag);
907 dcc->iotag = 0;
908 }
909 return FALSE;
910 }
911 }
912 }
913 return TRUE;
914 }
915
916 static gboolean
write_proxy(struct DCC * dcc)917 write_proxy (struct DCC *dcc)
918 {
919 struct proxy_state *proxy = dcc->proxy;
920 while (proxy->bufferused < proxy->buffersize)
921 {
922 int ret = send (dcc->sok, &proxy->buffer[proxy->bufferused],
923 proxy->buffersize - proxy->bufferused, 0);
924 if (ret >= 0)
925 proxy->bufferused += ret;
926 else
927 {
928 if (would_block ())
929 return FALSE;
930 else
931 {
932 dcc->dccstat = STAT_FAILED;
933 fe_dcc_update (dcc);
934 if (dcc->wiotag)
935 {
936 fe_input_remove (dcc->wiotag);
937 dcc->wiotag = 0;
938 }
939 return FALSE;
940 }
941 }
942 }
943 return TRUE;
944 }
945
946 static gboolean
proxy_read_line(struct DCC * dcc)947 proxy_read_line (struct DCC *dcc)
948 {
949 struct proxy_state *proxy = dcc->proxy;
950 while (1)
951 {
952 proxy->buffersize = proxy->bufferused + 1;
953 if (!read_proxy (dcc))
954 return FALSE;
955 if (proxy->buffer[proxy->bufferused - 1] == '\n'
956 || proxy->bufferused == MAX_PROXY_BUFFER)
957 {
958 proxy->buffer[proxy->bufferused - 1] = 0;
959 return TRUE;
960 }
961 }
962 }
963
964 static gboolean
dcc_wingate_proxy_traverse(GIOChannel * source,GIOCondition condition,struct DCC * dcc)965 dcc_wingate_proxy_traverse (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
966 {
967 struct proxy_state *proxy = dcc->proxy;
968 if (proxy->phase == 0)
969 {
970 proxy->buffersize = g_snprintf ((char*) proxy->buffer, MAX_PROXY_BUFFER,
971 "%s %d\r\n", net_ip(dcc->addr),
972 dcc->port);
973 proxy->bufferused = 0;
974 dcc->wiotag = fe_input_add (dcc->sok, FIA_WRITE|FIA_EX,
975 dcc_wingate_proxy_traverse, dcc);
976 ++proxy->phase;
977 }
978 if (proxy->phase == 1)
979 {
980 if (!read_proxy (dcc))
981 return TRUE;
982 fe_input_remove (dcc->wiotag);
983 dcc->wiotag = 0;
984 dcc_connect_finished (source, 0, dcc);
985 }
986 return TRUE;
987 }
988
989 struct sock_connect
990 {
991 char version;
992 char type;
993 guint16 port;
994 guint32 address;
995 char username[10];
996 };
997 static gboolean
dcc_socks_proxy_traverse(GIOChannel * source,GIOCondition condition,struct DCC * dcc)998 dcc_socks_proxy_traverse (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
999 {
1000 struct proxy_state *proxy = dcc->proxy;
1001
1002 if (proxy->phase == 0)
1003 {
1004 struct sock_connect sc;
1005 sc.version = 4;
1006 sc.type = 1;
1007 sc.port = htons (dcc->port);
1008 sc.address = htonl (dcc->addr);
1009 g_strlcpy (sc.username, prefs.hex_irc_user_name, sizeof (sc.username));
1010 memcpy (proxy->buffer, &sc, sizeof (sc));
1011 proxy->buffersize = 8 + strlen (sc.username) + 1;
1012 proxy->bufferused = 0;
1013 dcc->wiotag = fe_input_add (dcc->sok, FIA_WRITE|FIA_EX,
1014 dcc_socks_proxy_traverse, dcc);
1015 ++proxy->phase;
1016 }
1017
1018 if (proxy->phase == 1)
1019 {
1020 if (!write_proxy (dcc))
1021 return TRUE;
1022 fe_input_remove (dcc->wiotag);
1023 dcc->wiotag = 0;
1024 proxy->bufferused = 0;
1025 proxy->buffersize = 8;
1026 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX,
1027 dcc_socks_proxy_traverse, dcc);
1028 ++proxy->phase;
1029 }
1030
1031 if (proxy->phase == 2)
1032 {
1033 if (!read_proxy (dcc))
1034 return TRUE;
1035 fe_input_remove (dcc->iotag);
1036 dcc->iotag = 0;
1037 if (proxy->buffer[1] == 90)
1038 dcc_connect_finished (source, 0, dcc);
1039 else
1040 {
1041 dcc->dccstat = STAT_FAILED;
1042 fe_dcc_update (dcc);
1043 }
1044 }
1045
1046 return TRUE;
1047 }
1048
1049 struct sock5_connect1
1050 {
1051 char version;
1052 char nmethods;
1053 char method;
1054 };
1055 static gboolean
dcc_socks5_proxy_traverse(GIOChannel * source,GIOCondition condition,struct DCC * dcc)1056 dcc_socks5_proxy_traverse (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
1057 {
1058 struct proxy_state *proxy = dcc->proxy;
1059 int auth = prefs.hex_net_proxy_auth && prefs.hex_net_proxy_user[0] && prefs.hex_net_proxy_pass[0];
1060
1061 if (proxy->phase == 0)
1062 {
1063 struct sock5_connect1 sc1;
1064
1065 sc1.version = 5;
1066 sc1.nmethods = 1;
1067 sc1.method = 0;
1068 if (auth)
1069 sc1.method = 2;
1070 memcpy (proxy->buffer, &sc1, 3);
1071 proxy->buffersize = 3;
1072 proxy->bufferused = 0;
1073 dcc->wiotag = fe_input_add (dcc->sok, FIA_WRITE|FIA_EX,
1074 dcc_socks5_proxy_traverse, dcc);
1075 ++proxy->phase;
1076 }
1077
1078 if (proxy->phase == 1)
1079 {
1080 if (!write_proxy (dcc))
1081 return TRUE;
1082 fe_input_remove (dcc->wiotag);
1083 dcc->wiotag = 0;
1084 proxy->bufferused = 0;
1085 proxy->buffersize = 2;
1086 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX,
1087 dcc_socks5_proxy_traverse, dcc);
1088 ++proxy->phase;
1089 }
1090
1091 if (proxy->phase == 2)
1092 {
1093 if (!read_proxy (dcc))
1094 return TRUE;
1095 fe_input_remove (dcc->iotag);
1096 dcc->iotag = 0;
1097
1098 /* did the server say no auth required? */
1099 if (proxy->buffer[0] == 5 && proxy->buffer[1] == 0)
1100 auth = 0;
1101
1102 /* Set up authentication I/O */
1103 if (auth)
1104 {
1105 int len_u=0, len_p=0;
1106
1107 /* authentication sub-negotiation (RFC1929) */
1108 if ( proxy->buffer[0] != 5 || proxy->buffer[1] != 2 ) /* UPA not supported by server */
1109 {
1110 PrintText (dcc->serv->front_session, "SOCKS\tServer doesn't support UPA authentication.\n");
1111 dcc->dccstat = STAT_FAILED;
1112 fe_dcc_update (dcc);
1113 return TRUE;
1114 }
1115
1116 memset (proxy->buffer, 0, MAX_PROXY_BUFFER);
1117
1118 /* form the UPA request */
1119 len_u = strlen (prefs.hex_net_proxy_user);
1120 len_p = strlen (prefs.hex_net_proxy_pass);
1121 proxy->buffer[0] = 1;
1122 proxy->buffer[1] = len_u;
1123 memcpy (proxy->buffer + 2, prefs.hex_net_proxy_user, len_u);
1124 proxy->buffer[2 + len_u] = len_p;
1125 memcpy (proxy->buffer + 3 + len_u, prefs.hex_net_proxy_pass, len_p);
1126
1127 proxy->buffersize = 3 + len_u + len_p;
1128 proxy->bufferused = 0;
1129 dcc->wiotag = fe_input_add (dcc->sok, FIA_WRITE|FIA_EX,
1130 dcc_socks5_proxy_traverse, dcc);
1131 ++proxy->phase;
1132 }
1133 else
1134 {
1135 if (proxy->buffer[0] != 5 || proxy->buffer[1] != 0)
1136 {
1137 PrintText (dcc->serv->front_session, "SOCKS\tAuthentication required but disabled in settings.\n");
1138 dcc->dccstat = STAT_FAILED;
1139 fe_dcc_update (dcc);
1140 return TRUE;
1141 }
1142 proxy->phase += 2;
1143 }
1144 }
1145
1146 if (proxy->phase == 3)
1147 {
1148 if (!write_proxy (dcc))
1149 return TRUE;
1150 fe_input_remove (dcc->wiotag);
1151 dcc->wiotag = 0;
1152 proxy->buffersize = 2;
1153 proxy->bufferused = 0;
1154 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX,
1155 dcc_socks5_proxy_traverse, dcc);
1156 ++proxy->phase;
1157 }
1158
1159 if (proxy->phase == 4)
1160 {
1161 if (!read_proxy (dcc))
1162 return TRUE;
1163 if (dcc->iotag)
1164 {
1165 fe_input_remove (dcc->iotag);
1166 dcc->iotag = 0;
1167 }
1168 if (proxy->buffer[1] != 0)
1169 {
1170 PrintText (dcc->serv->front_session, "SOCKS\tAuthentication failed. "
1171 "Is username and password correct?\n");
1172 dcc->dccstat = STAT_FAILED;
1173 fe_dcc_update (dcc);
1174 return TRUE;
1175 }
1176 ++proxy->phase;
1177 }
1178
1179 if (proxy->phase == 5)
1180 {
1181 proxy->buffer[0] = 5; /* version (socks 5) */
1182 proxy->buffer[1] = 1; /* command (connect) */
1183 proxy->buffer[2] = 0; /* reserved */
1184 proxy->buffer[3] = 1; /* address type (IPv4) */
1185 proxy->buffer[4] = (dcc->addr >> 24) & 0xFF; /* IP address */
1186 proxy->buffer[5] = (dcc->addr >> 16) & 0xFF;
1187 proxy->buffer[6] = (dcc->addr >> 8) & 0xFF;
1188 proxy->buffer[7] = (dcc->addr & 0xFF);
1189 proxy->buffer[8] = (dcc->port >> 8) & 0xFF; /* port */
1190 proxy->buffer[9] = (dcc->port & 0xFF);
1191 proxy->buffersize = 10;
1192 proxy->bufferused = 0;
1193 dcc->wiotag = fe_input_add (dcc->sok, FIA_WRITE|FIA_EX,
1194 dcc_socks5_proxy_traverse, dcc);
1195 ++proxy->phase;
1196 }
1197
1198 if (proxy->phase == 6)
1199 {
1200 if (!write_proxy (dcc))
1201 return TRUE;
1202 fe_input_remove (dcc->wiotag);
1203 dcc->wiotag = 0;
1204 proxy->buffersize = 4;
1205 proxy->bufferused = 0;
1206 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX,
1207 dcc_socks5_proxy_traverse, dcc);
1208 ++proxy->phase;
1209 }
1210
1211 if (proxy->phase == 7)
1212 {
1213 if (!read_proxy (dcc))
1214 return TRUE;
1215 if (proxy->buffer[0] != 5 || proxy->buffer[1] != 0)
1216 {
1217 fe_input_remove (dcc->iotag);
1218 dcc->iotag = 0;
1219 if (proxy->buffer[1] == 2)
1220 PrintText (dcc->serv->front_session, "SOCKS\tProxy refused to connect to host (not allowed).\n");
1221 else
1222 PrintTextf (dcc->serv->front_session, "SOCKS\tProxy failed to connect to host (error %d).\n", proxy->buffer[1]);
1223 dcc->dccstat = STAT_FAILED;
1224 fe_dcc_update (dcc);
1225 return TRUE;
1226 }
1227 switch (proxy->buffer[3])
1228 {
1229 case 1: proxy->buffersize += 6; break;
1230 case 3: proxy->buffersize += 1; break;
1231 case 4: proxy->buffersize += 18; break;
1232 };
1233 ++proxy->phase;
1234 }
1235
1236 if (proxy->phase == 8)
1237 {
1238 if (!read_proxy (dcc))
1239 return TRUE;
1240 /* handle domain name case */
1241 if (proxy->buffer[3] == 3)
1242 {
1243 proxy->buffersize = 5 + proxy->buffer[4] + 2;
1244 }
1245 /* everything done? */
1246 if (proxy->bufferused == proxy->buffersize)
1247 {
1248 fe_input_remove (dcc->iotag);
1249 dcc->iotag = 0;
1250 dcc_connect_finished (source, 0, dcc);
1251 }
1252 }
1253 return TRUE;
1254 }
1255
1256 static gboolean
dcc_http_proxy_traverse(GIOChannel * source,GIOCondition condition,struct DCC * dcc)1257 dcc_http_proxy_traverse (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
1258 {
1259 struct proxy_state *proxy = dcc->proxy;
1260
1261 if (proxy->phase == 0)
1262 {
1263 char buf[256];
1264 char auth_data[128];
1265 char auth_data2[68];
1266 int n, n2;
1267
1268 n = g_snprintf (buf, sizeof (buf), "CONNECT %s:%d HTTP/1.0\r\n",
1269 net_ip(dcc->addr), dcc->port);
1270 if (prefs.hex_net_proxy_auth)
1271 {
1272 n2 = g_snprintf (auth_data2, sizeof (auth_data2), "%s:%s",
1273 prefs.hex_net_proxy_user, prefs.hex_net_proxy_pass);
1274 base64_encode (auth_data, auth_data2, n2);
1275 n += g_snprintf (buf+n, sizeof (buf)-n, "Proxy-Authorization: Basic %s\r\n", auth_data);
1276 }
1277 n += g_snprintf (buf+n, sizeof (buf)-n, "\r\n");
1278 proxy->buffersize = n;
1279 proxy->bufferused = 0;
1280 memcpy (proxy->buffer, buf, proxy->buffersize);
1281 dcc->wiotag = fe_input_add (dcc->sok, FIA_WRITE|FIA_EX,
1282 dcc_http_proxy_traverse, dcc);
1283 ++proxy->phase;
1284 }
1285
1286 if (proxy->phase == 1)
1287 {
1288 if (!write_proxy (dcc))
1289 return TRUE;
1290 fe_input_remove (dcc->wiotag);
1291 dcc->wiotag = 0;
1292 proxy->bufferused = 0;
1293 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX,
1294 dcc_http_proxy_traverse, dcc);
1295 ++proxy->phase;
1296 }
1297
1298 if (proxy->phase == 2)
1299 {
1300 if (!proxy_read_line (dcc))
1301 return TRUE;
1302 /* "HTTP/1.0 200 OK" */
1303 if (proxy->bufferused < 12 ||
1304 memcmp (proxy->buffer, "HTTP/", 5) || memcmp (proxy->buffer + 9, "200", 3))
1305 {
1306 fe_input_remove (dcc->iotag);
1307 dcc->iotag = 0;
1308 PrintText (dcc->serv->front_session, proxy->buffer);
1309 dcc->dccstat = STAT_FAILED;
1310 fe_dcc_update (dcc);
1311 return TRUE;
1312 }
1313 proxy->bufferused = 0;
1314 ++proxy->phase;
1315 }
1316
1317 if (proxy->phase == 3)
1318 {
1319 while (1)
1320 {
1321 /* read until blank line */
1322 if (proxy_read_line (dcc))
1323 {
1324 if (proxy->bufferused < 1 ||
1325 (proxy->bufferused == 2 && proxy->buffer[0] == '\r'))
1326 {
1327 break;
1328 }
1329 if (proxy->bufferused > 1)
1330 PrintText (dcc->serv->front_session, proxy->buffer);
1331 proxy->bufferused = 0;
1332 }
1333 else
1334 return TRUE;
1335 }
1336 fe_input_remove (dcc->iotag);
1337 dcc->iotag = 0;
1338 dcc_connect_finished (source, 0, dcc);
1339 }
1340
1341 return TRUE;
1342 }
1343
1344 static gboolean
dcc_proxy_connect(GIOChannel * source,GIOCondition condition,struct DCC * dcc)1345 dcc_proxy_connect (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
1346 {
1347 fe_input_remove (dcc->iotag);
1348 dcc->iotag = 0;
1349
1350 if (!dcc_did_connect (source, condition, dcc))
1351 return TRUE;
1352
1353 dcc->proxy = g_new0 (struct proxy_state, 1);
1354
1355 switch (prefs.hex_net_proxy_type)
1356 {
1357 case 1: return dcc_wingate_proxy_traverse (source, condition, dcc);
1358 case 2: return dcc_socks_proxy_traverse (source, condition, dcc);
1359 case 3: return dcc_socks5_proxy_traverse (source, condition, dcc);
1360 case 4: return dcc_http_proxy_traverse (source, condition, dcc);
1361 }
1362 return TRUE;
1363 }
1364
1365 static int dcc_listen_init (struct DCC *, struct session *);
1366
1367 static void
dcc_connect(struct DCC * dcc)1368 dcc_connect (struct DCC *dcc)
1369 {
1370 int ret;
1371 char tbuf[400];
1372
1373 if (dcc->dccstat == STAT_CONNECTING)
1374 return;
1375 dcc->dccstat = STAT_CONNECTING;
1376
1377 if (dcc->pasvid && dcc->port == 0)
1378 {
1379 /* accepted a passive dcc send */
1380 ret = dcc_listen_init (dcc, dcc->serv->front_session);
1381 if (!ret)
1382 {
1383 dcc_close (dcc, STAT_FAILED, FALSE);
1384 return;
1385 }
1386 /* possible problems with filenames containing spaces? */
1387 if (dcc->type == TYPE_RECV)
1388 g_snprintf (tbuf, sizeof (tbuf), strchr (dcc->file, ' ') ?
1389 "DCC SEND \"%s\" %u %d %" G_GUINT64_FORMAT " %d" :
1390 "DCC SEND %s %u %d %" G_GUINT64_FORMAT " %d", dcc->file,
1391 dcc->addr, dcc->port, dcc->size, dcc->pasvid);
1392 else
1393 g_snprintf (tbuf, sizeof (tbuf), "DCC CHAT chat %u %d %d",
1394 dcc->addr, dcc->port, dcc->pasvid);
1395 dcc->serv->p_ctcp (dcc->serv, dcc->nick, tbuf);
1396 }
1397 else
1398 {
1399 dcc->sok = dcc_connect_sok (dcc);
1400 if (dcc->sok == -1)
1401 {
1402 dcc->dccstat = STAT_FAILED;
1403 fe_dcc_update (dcc);
1404 return;
1405 }
1406 if (DCC_USE_PROXY ())
1407 dcc->iotag = fe_input_add (dcc->sok, FIA_WRITE|FIA_EX, dcc_proxy_connect, dcc);
1408 else
1409 dcc->iotag = fe_input_add (dcc->sok, FIA_WRITE|FIA_EX, dcc_connect_finished, dcc);
1410 }
1411
1412 fe_dcc_update (dcc);
1413 }
1414
1415 static gboolean
dcc_send_data(GIOChannel * source,GIOCondition condition,struct DCC * dcc)1416 dcc_send_data (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
1417 {
1418 char *buf;
1419 int len, sent, sok = dcc->sok;
1420
1421 if (prefs.hex_dcc_blocksize < 1) /* this is too little! */
1422 prefs.hex_dcc_blocksize = 1024;
1423
1424 if (prefs.hex_dcc_blocksize > 102400) /* this is too much! */
1425 prefs.hex_dcc_blocksize = 102400;
1426
1427 if (dcc->throttled)
1428 {
1429 fe_input_remove (dcc->wiotag);
1430 dcc->wiotag = 0;
1431 return FALSE;
1432 }
1433
1434 if (!dcc->fastsend)
1435 {
1436 if (dcc->ack < (dcc->pos & 0xFFFFFFFF))
1437 return TRUE;
1438 }
1439 else if (!dcc->wiotag)
1440 dcc->wiotag = fe_input_add (sok, FIA_WRITE, dcc_send_data, dcc);
1441
1442 buf = g_malloc (prefs.hex_dcc_blocksize);
1443
1444 lseek (dcc->fp, dcc->pos, SEEK_SET);
1445 len = read (dcc->fp, buf, prefs.hex_dcc_blocksize);
1446 if (len < 1)
1447 goto abortit;
1448 sent = send (sok, buf, len, 0);
1449
1450 if (sent < 0 && !(would_block ()))
1451 {
1452 abortit:
1453 g_free (buf);
1454 EMIT_SIGNAL (XP_TE_DCCSENDFAIL, dcc->serv->front_session,
1455 file_part (dcc->file), dcc->nick,
1456 errorstring (sock_error ()), NULL, 0);
1457 dcc_close (dcc, STAT_FAILED, FALSE);
1458 return TRUE;
1459 }
1460 if (sent > 0)
1461 {
1462 dcc->pos += sent;
1463 dcc->lasttime = time (0);
1464 }
1465
1466 /* have we sent it all yet? */
1467 if (dcc->pos >= dcc->size)
1468 {
1469 /* it's all sent now, so remove the WRITE/SEND handler */
1470 if (dcc->wiotag)
1471 {
1472 fe_input_remove (dcc->wiotag);
1473 dcc->wiotag = 0;
1474 }
1475 }
1476
1477 g_free (buf);
1478
1479 return TRUE;
1480 }
1481
1482 static gboolean
dcc_handle_new_ack(struct DCC * dcc)1483 dcc_handle_new_ack (struct DCC *dcc)
1484 {
1485 guint32 ack;
1486 char buf[16];
1487 gboolean done = FALSE;
1488
1489 memcpy (&ack, dcc->ack_buf, 4);
1490 dcc->ack = ntohl (ack);
1491
1492 /* this could mess up when xfering >32bit files */
1493 if (dcc->size <= 0xffffffff)
1494 {
1495 /* fix for BitchX */
1496 if (dcc->ack < dcc->resumable)
1497 dcc->ackoffset = TRUE;
1498 if (dcc->ackoffset)
1499 dcc->ack += dcc->resumable;
1500 }
1501
1502 /* DCC complete check */
1503 if (dcc->pos >= dcc->size && dcc->ack >= (dcc->size & 0xffffffff))
1504 {
1505 dcc->ack = dcc->size; /* force 100% ack for >4 GB */
1506 dcc_close (dcc, STAT_DONE, FALSE);
1507 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 */
1508 /* cppcheck-suppress deallocuse */
1509 sprintf (buf, "%" G_GINT64_FORMAT, dcc->cps);
1510 EMIT_SIGNAL (XP_TE_DCCSENDCOMP, dcc->serv->front_session,
1511 file_part (dcc->file), dcc->nick, buf, NULL, 0);
1512 done = TRUE;
1513 }
1514 else if ((!dcc->fastsend) && (dcc->ack >= (dcc->pos & 0xffffffff)))
1515 {
1516 dcc_send_data (NULL, 0, (gpointer)dcc);
1517 }
1518
1519 /* take the top 32 of "bytes send" and bottom 32 of "ack" */
1520 dcc->ack = (dcc->pos & G_GINT64_CONSTANT (0xffffffff00000000)) |
1521 (dcc->ack & 0xffffffff);
1522 /* dcc->ack is only used for CPS and PERCENTAGE calcs from now on... */
1523
1524 return done;
1525 }
1526
1527 static gboolean
dcc_read_ack(GIOChannel * source,GIOCondition condition,struct DCC * dcc)1528 dcc_read_ack (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
1529 {
1530 int len;
1531
1532 while (1)
1533 {
1534 /* try to fill up 4 bytes */
1535 len = recv (dcc->sok, dcc->ack_buf, 4 - dcc->ack_pos, 0);
1536 if (len < 1)
1537 {
1538 if (len < 0)
1539 {
1540 if (would_block ()) /* ok - keep waiting */
1541 return TRUE;
1542 }
1543 EMIT_SIGNAL (XP_TE_DCCSENDFAIL, dcc->serv->front_session,
1544 file_part (dcc->file), dcc->nick,
1545 errorstring ((len < 0) ? sock_error () : 0), NULL, 0);
1546 dcc_close (dcc, STAT_FAILED, FALSE);
1547 return TRUE;
1548 }
1549
1550 dcc->ack_pos += len;
1551 if (dcc->ack_pos >= 4)
1552 {
1553 dcc->ack_pos = 0;
1554 if (dcc_handle_new_ack (dcc))
1555 return TRUE;
1556 }
1557 /* loop again until would_block() returns true */
1558 }
1559 }
1560
1561 static gboolean
dcc_accept(GIOChannel * source,GIOCondition condition,struct DCC * dcc)1562 dcc_accept (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
1563 {
1564 char host[128];
1565 struct sockaddr_in CAddr;
1566 int sok;
1567 socklen_t len;
1568
1569 len = sizeof (CAddr);
1570 sok = accept (dcc->sok, (struct sockaddr *) &CAddr, &len);
1571 fe_input_remove (dcc->iotag);
1572 dcc->iotag = 0;
1573 closesocket (dcc->sok);
1574 if (sok < 0)
1575 {
1576 dcc->sok = -1;
1577 dcc_close (dcc, STAT_FAILED, FALSE);
1578 return TRUE;
1579 }
1580 set_nonblocking (sok);
1581 dcc->sok = sok;
1582 dcc->addr = ntohl (CAddr.sin_addr.s_addr);
1583
1584 if (dcc->pasvid)
1585 return dcc_connect_finished (NULL, 0, dcc);
1586
1587 dcc->dccstat = STAT_ACTIVE;
1588 dcc->lasttime = dcc->starttime = time (0);
1589 dcc->fastsend = prefs.hex_dcc_fast_send;
1590
1591 g_snprintf (host, sizeof (host), "%s:%d", net_ip (dcc->addr), dcc->port);
1592
1593 switch (dcc->type)
1594 {
1595 case TYPE_SEND:
1596 if (dcc->fastsend)
1597 dcc->wiotag = fe_input_add (sok, FIA_WRITE, dcc_send_data, dcc);
1598 dcc->iotag = fe_input_add (sok, FIA_READ|FIA_EX, dcc_read_ack, dcc);
1599 dcc_send_data (NULL, 0, (gpointer)dcc);
1600 EMIT_SIGNAL (XP_TE_DCCCONSEND, dcc->serv->front_session,
1601 dcc->nick, host, dcc->file, NULL, 0);
1602 break;
1603
1604 case TYPE_CHATSEND:
1605 dcc_open_query (dcc->serv, dcc->nick);
1606 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX, dcc_read_chat, dcc);
1607 dcc->dccchat = g_new0 (struct dcc_chat, 1);
1608 EMIT_SIGNAL (XP_TE_DCCCONCHAT, dcc->serv->front_session,
1609 dcc->nick, host, NULL, NULL, 0);
1610 break;
1611 default:
1612 break;
1613 }
1614
1615 fe_dcc_update (dcc);
1616
1617 return TRUE;
1618 }
1619
1620 guint32
dcc_get_my_address(session * sess)1621 dcc_get_my_address (session *sess) /* the address we'll tell the other person */
1622 {
1623 struct hostent *dns_query;
1624 guint32 addr = 0;
1625
1626 if (prefs.hex_dcc_ip_from_server && sess->server->dcc_ip)
1627 addr = sess->server->dcc_ip;
1628 else if (prefs.hex_dcc_ip[0])
1629 {
1630 dns_query = gethostbyname ((const char *) prefs.hex_dcc_ip);
1631
1632 if (dns_query != NULL &&
1633 dns_query->h_length == 4 &&
1634 dns_query->h_addr_list[0] != NULL)
1635 {
1636 /*we're offered at least one IPv4 address: we take the first*/
1637 addr = *((guint32*) dns_query->h_addr_list[0]);
1638 }
1639 }
1640
1641 return addr;
1642 }
1643
1644 static int
dcc_listen_init(struct DCC * dcc,session * sess)1645 dcc_listen_init (struct DCC *dcc, session *sess)
1646 {
1647 guint32 my_addr;
1648 struct sockaddr_in SAddr;
1649 int i, bindretval = -1;
1650 socklen_t len;
1651
1652 dcc->sok = socket (AF_INET, SOCK_STREAM, 0);
1653 if (dcc->sok == -1)
1654 return FALSE;
1655
1656 memset (&SAddr, 0, sizeof (struct sockaddr_in));
1657
1658 len = sizeof (SAddr);
1659 getsockname (dcc->serv->sok, (struct sockaddr *) &SAddr, &len);
1660
1661 SAddr.sin_family = AF_INET;
1662
1663 /*if local_ip is specified use that*/
1664 if (prefs.local_ip != 0xffffffff)
1665 {
1666 my_addr = prefs.local_ip;
1667 SAddr.sin_addr.s_addr = prefs.local_ip;
1668 }
1669 /*otherwise use the default*/
1670 else
1671 my_addr = SAddr.sin_addr.s_addr;
1672
1673 /*if we have a valid portrange try to use that*/
1674 if (prefs.hex_dcc_port_first > 0)
1675 {
1676 SAddr.sin_port = 0;
1677 i = 0;
1678 while ((prefs.hex_dcc_port_last > ntohs(SAddr.sin_port)) &&
1679 (bindretval == -1))
1680 {
1681 SAddr.sin_port = htons (prefs.hex_dcc_port_first + i);
1682 i++;
1683 /*printf("Trying to bind against port: %d\n",ntohs(SAddr.sin_port));*/
1684 bindretval = bind (dcc->sok, (struct sockaddr *) &SAddr, sizeof (SAddr));
1685 }
1686
1687 /* with a small port range, reUseAddr is needed */
1688 len = 1;
1689 setsockopt (dcc->sok, SOL_SOCKET, SO_REUSEADDR, (char *) &len, sizeof (len));
1690
1691 } else
1692 {
1693 /* try random port */
1694 SAddr.sin_port = 0;
1695 bindretval = bind (dcc->sok, (struct sockaddr *) &SAddr, sizeof (SAddr));
1696 }
1697
1698 if (bindretval == -1)
1699 {
1700 /* failed to bind */
1701 PrintText (sess, "Failed to bind to any address or port.\n");
1702 return FALSE;
1703 }
1704
1705 len = sizeof (SAddr);
1706 getsockname (dcc->sok, (struct sockaddr *) &SAddr, &len);
1707
1708 dcc->port = ntohs (SAddr.sin_port);
1709
1710 /*if we have a dcc_ip, we use that, so the remote client can connect*/
1711 /*else we try to take an address from hex_dcc_ip*/
1712 /*if something goes wrong we tell the client to connect to our LAN ip*/
1713 dcc->addr = dcc_get_my_address (sess);
1714
1715 /*if nothing else worked we use the address we bound to*/
1716 if (dcc->addr == 0)
1717 dcc->addr = my_addr;
1718
1719 dcc->addr = ntohl (dcc->addr);
1720
1721 set_nonblocking (dcc->sok);
1722 listen (dcc->sok, 1);
1723 set_blocking (dcc->sok);
1724
1725 dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX, dcc_accept, dcc);
1726
1727 return TRUE;
1728 }
1729
1730 static struct session *dccsess;
1731 static char *dccto; /* lame!! */
1732 static gint64 dccmaxcps;
1733 static int recursive = FALSE;
1734
1735 static void
dcc_send_wild(char * file)1736 dcc_send_wild (char *file)
1737 {
1738 dcc_send (dccsess, dccto, file, dccmaxcps, 0);
1739 }
1740
1741 void
dcc_send(struct session * sess,char * to,char * filename,gint64 maxcps,int passive)1742 dcc_send (struct session *sess, char *to, char *filename, gint64 maxcps, int passive)
1743 {
1744 char outbuf[512];
1745 GFileInfo *file_info;
1746 GFile *file;
1747 struct DCC *dcc;
1748 gchar *filename_fs;
1749 GFileType file_type;
1750 goffset file_size;
1751
1752 filename = expand_homedir (filename);
1753
1754 if (!recursive && (strchr (filename, '*') || strchr (filename, '?')))
1755 {
1756 char path[256];
1757 char wild[256];
1758
1759 safe_strcpy (wild, file_part (filename), sizeof (wild));
1760 path_part (filename, path, sizeof (path));
1761 if (path[0] != '/' || path[1] != '\0')
1762 path[strlen (path) - 1] = 0; /* remove trailing slash */
1763
1764 dccsess = sess;
1765 dccto = to;
1766 dccmaxcps = maxcps;
1767
1768 g_free (filename);
1769
1770 recursive = TRUE;
1771 for_files (path, wild, dcc_send_wild);
1772 recursive = FALSE;
1773
1774 return;
1775 }
1776
1777 dcc = new_dcc ();
1778 if (!dcc)
1779 {
1780 g_free (filename);
1781 return;
1782 }
1783
1784 dcc->file = filename;
1785 dcc->maxcps = maxcps;
1786
1787 filename_fs = g_filename_from_utf8 (filename, -1, NULL, NULL, NULL);
1788 if (filename_fs == NULL)
1789 {
1790 PrintTextf (sess, _("Cannot access %s\n"), dcc->file);
1791 PrintTextf (sess, "%s %d: %s\n", _("Error"), errno, errorstring (errno));
1792
1793 dcc_close (dcc, 0, TRUE); /* dcc_close will free dcc->file */
1794
1795 return;
1796 }
1797
1798 file = g_file_new_for_path (filename_fs);
1799 if (file == NULL)
1800 {
1801 PrintTextf (sess, _("Cannot access %s\n"), dcc->file);
1802 PrintTextf (sess, "%s %d: %s\n", _("Error"), errno, errorstring (errno));
1803
1804 dcc_close (dcc, 0, TRUE); /* dcc_close will free dcc->file */
1805
1806 g_free (filename_fs);
1807
1808 return;
1809 }
1810
1811 file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_SIZE "," G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, NULL, NULL);
1812
1813 g_object_unref (file);
1814
1815 if (file_info == NULL)
1816 {
1817 PrintTextf (sess, _("Cannot access %s\n"), dcc->file);
1818 PrintTextf (sess, "%s %d: %s\n", _("Error"), errno, errorstring (errno));
1819
1820 dcc_close (dcc, 0, TRUE); /* dcc_close will free dcc->file */
1821
1822 g_free (filename_fs);
1823
1824 return;
1825 }
1826
1827 file_type = g_file_info_get_file_type (file_info);
1828 file_size = g_file_info_get_size (file_info);
1829
1830 g_object_unref (file_info);
1831
1832 if (*file_part (filename) == '\0' || file_type == G_FILE_TYPE_DIRECTORY || file_size <= 0)
1833 {
1834 PrintText (sess, "Cannot send directories or empty files.\n");
1835
1836 dcc_close (dcc, 0, TRUE); /* dcc_close will free dcc->file */
1837
1838 g_free (filename_fs);
1839
1840 return;
1841 }
1842
1843 dcc->starttime = dcc->offertime = time (0);
1844 dcc->serv = sess->server;
1845 dcc->dccstat = STAT_QUEUED;
1846 dcc->size = file_size;
1847 dcc->type = TYPE_SEND;
1848 dcc->fp = g_open (filename_fs, OFLAGS | O_RDONLY, 0);
1849
1850 g_free (filename_fs);
1851
1852 if (dcc->fp == -1)
1853 {
1854 PrintText (sess, "Cannot send directories or empty files.\n");
1855
1856 dcc_close (dcc, 0, TRUE); /* dcc_close will free dcc->file */
1857
1858 return;
1859 }
1860
1861 if (passive || dcc_listen_init (dcc, sess))
1862 {
1863 char havespaces = 0;
1864 while (*filename)
1865 {
1866 if (*filename == ' ')
1867 {
1868 if (prefs.hex_dcc_send_fillspaces)
1869 *filename = '_';
1870 else
1871 havespaces = 1;
1872 }
1873 filename++;
1874 }
1875 dcc->nick = g_strdup (to);
1876 if (prefs.hex_gui_autoopen_send)
1877 {
1878 if (fe_dcc_open_send_win (TRUE)) /* already open? add */
1879 fe_dcc_add (dcc);
1880 } else
1881 fe_dcc_add (dcc);
1882
1883 if (passive)
1884 {
1885 dcc->pasvid = new_id();
1886 g_snprintf (outbuf, sizeof (outbuf), (havespaces) ?
1887 "DCC SEND \"%s\" 199 0 %" G_GUINT64_FORMAT " %d" :
1888 "DCC SEND %s 199 0 %" G_GUINT64_FORMAT " %d",
1889 file_part (dcc->file),
1890 dcc->size, dcc->pasvid);
1891 }
1892 else
1893 {
1894 g_snprintf (outbuf, sizeof (outbuf), (havespaces) ?
1895 "DCC SEND \"%s\" %u %d %" G_GUINT64_FORMAT :
1896 "DCC SEND %s %u %d %" G_GUINT64_FORMAT,
1897 file_part (dcc->file), dcc->addr,
1898 dcc->port, dcc->size);
1899 }
1900 sess->server->p_ctcp (sess->server, to, outbuf);
1901
1902 EMIT_SIGNAL (XP_TE_DCCOFFER, sess, file_part (dcc->file),
1903 to, dcc->file, NULL, 0);
1904 }
1905 else
1906 {
1907 dcc_close (dcc, 0, TRUE);
1908 }
1909 }
1910
1911 static struct DCC *
find_dcc_from_id(int id,int type)1912 find_dcc_from_id (int id, int type)
1913 {
1914 struct DCC *dcc;
1915 GSList *list = dcc_list;
1916 while (list)
1917 {
1918 dcc = (struct DCC *) list->data;
1919 if (dcc->pasvid == id &&
1920 dcc->dccstat == STAT_QUEUED && dcc->type == type)
1921 return dcc;
1922 list = list->next;
1923 }
1924 return NULL;
1925 }
1926
1927 static struct DCC *
find_dcc_from_port(int port,int type)1928 find_dcc_from_port (int port, int type)
1929 {
1930 struct DCC *dcc;
1931 GSList *list = dcc_list;
1932 while (list)
1933 {
1934 dcc = (struct DCC *) list->data;
1935 if (dcc->port == port &&
1936 dcc->dccstat == STAT_QUEUED && dcc->type == type)
1937 return dcc;
1938 list = list->next;
1939 }
1940 return NULL;
1941 }
1942
1943 struct DCC *
find_dcc(char * nick,char * file,int type)1944 find_dcc (char *nick, char *file, int type)
1945 {
1946 GSList *list = dcc_list;
1947 struct DCC *dcc;
1948 while (list)
1949 {
1950 dcc = (struct DCC *) list->data;
1951 if (nick == NULL || !rfc_casecmp (nick, dcc->nick))
1952 {
1953 if (type == -1 || dcc->type == type)
1954 {
1955 if (!file[0])
1956 return dcc;
1957 if (!g_ascii_strcasecmp (file, file_part (dcc->file)))
1958 return dcc;
1959 if (!g_ascii_strcasecmp (file, dcc->file))
1960 return dcc;
1961 }
1962 }
1963 list = list->next;
1964 }
1965 return NULL;
1966 }
1967
1968 /* called when we receive a NICK change from server */
1969
1970 void
dcc_change_nick(struct server * serv,char * oldnick,char * newnick)1971 dcc_change_nick (struct server *serv, char *oldnick, char *newnick)
1972 {
1973 struct DCC *dcc;
1974 GSList *list = dcc_list;
1975
1976 while (list)
1977 {
1978 dcc = (struct DCC *) list->data;
1979 if (dcc->serv == serv)
1980 {
1981 if (!serv->p_cmp (dcc->nick, oldnick))
1982 {
1983 g_free (dcc->nick);
1984 dcc->nick = g_strdup (newnick);
1985 }
1986 }
1987 list = list->next;
1988 }
1989 }
1990
1991 /* is the destination file the same? new_dcc is not opened yet */
1992
1993 static gboolean
is_same_file(struct DCC * dcc,struct DCC * new_dcc)1994 is_same_file (struct DCC *dcc, struct DCC *new_dcc)
1995 {
1996 gboolean result = FALSE;
1997 gchar *filename_fs = NULL, *new_filename_fs = NULL;
1998 GFile *file = NULL, *new_file = NULL;
1999 GFileInfo *file_info = NULL, *new_file_info = NULL;
2000 char *file_id = NULL, *new_file_id = NULL;
2001 char *filesystem_id = NULL, *new_filesystem_id = NULL;
2002
2003 /* if it's the same filename, must be same */
2004 if (strcmp (dcc->destfile, new_dcc->destfile) == 0)
2005 {
2006 return TRUE;
2007 }
2008
2009 filename_fs = g_filename_from_utf8 (dcc->file, -1, NULL, NULL, NULL);
2010 if (filename_fs == NULL)
2011 {
2012 goto exit;
2013 }
2014
2015 new_filename_fs = g_filename_from_utf8 (new_dcc->file, -1, NULL, NULL, NULL);
2016 if (new_filename_fs == NULL)
2017 {
2018 goto exit;
2019 }
2020
2021 file = g_file_new_for_path (filename_fs);
2022 if (file == NULL)
2023 {
2024 goto exit;
2025 }
2026
2027 new_file = g_file_new_for_path (new_filename_fs);
2028 if (new_file == NULL)
2029 {
2030 goto exit;
2031 }
2032
2033 file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_ID_FILE "," G_FILE_ATTRIBUTE_ID_FILESYSTEM, G_FILE_QUERY_INFO_NONE, NULL, NULL);
2034 if (file_info == NULL)
2035 {
2036 goto exit;
2037 }
2038
2039 new_file_info = g_file_query_info (new_file, G_FILE_ATTRIBUTE_ID_FILE "," G_FILE_ATTRIBUTE_ID_FILESYSTEM, G_FILE_QUERY_INFO_NONE, NULL, NULL);
2040 if (new_file_info == NULL)
2041 {
2042 goto exit;
2043 }
2044
2045 file_id = g_file_info_get_attribute_as_string (file_info, G_FILE_ATTRIBUTE_ID_FILE);
2046 new_file_id = g_file_info_get_attribute_as_string (new_file_info, G_FILE_ATTRIBUTE_ID_FILE);
2047
2048 filesystem_id = g_file_info_get_attribute_as_string (file_info, G_FILE_ATTRIBUTE_ID_FILE);
2049 new_filesystem_id = g_file_info_get_attribute_as_string (new_file_info, G_FILE_ATTRIBUTE_ID_FILE);
2050
2051 if (file_id != NULL && new_file_id != NULL && filesystem_id != NULL && new_filesystem_id != NULL && strcmp (file_id, new_file_id) == 0 && strcmp (filesystem_id, new_filesystem_id) == 0)
2052 {
2053 result = TRUE;
2054 }
2055
2056 exit:
2057 g_free (filename_fs);
2058 g_free (new_filename_fs);
2059
2060 if (file != NULL)
2061 {
2062 g_object_unref (file);
2063 }
2064
2065 if (new_file != NULL)
2066 {
2067 g_object_unref (new_file);
2068 }
2069
2070 if (file_info != NULL)
2071 {
2072 g_object_unref (file_info);
2073 }
2074
2075 if (new_file_info != NULL)
2076 {
2077 g_object_unref (new_file_info);
2078 }
2079
2080 g_free (file_id);
2081 g_free (new_file_id);
2082 g_free(filesystem_id);
2083 g_free(new_filesystem_id);
2084
2085 return result;
2086 }
2087
2088 static void
update_is_resumable(struct DCC * dcc)2089 update_is_resumable (struct DCC *dcc)
2090 {
2091 gchar *filename_fs = g_filename_from_utf8 (dcc->destfile, -1, NULL, NULL, NULL);
2092
2093 dcc->resumable = 0;
2094
2095 /* Check the file size */
2096 if (filename_fs != NULL && g_access(filename_fs, W_OK) == 0)
2097 {
2098 GFile *file = g_file_new_for_path (filename_fs);
2099 if (file != NULL)
2100 {
2101 GFileInfo *file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_SIZE "," G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, NULL, NULL);
2102
2103 if (file_info != NULL)
2104 {
2105 goffset file_size_offset = g_file_info_get_size (file_info);
2106 guint64 file_size = (file_size_offset >= 0) ? (guint64) file_size_offset : 0;
2107 if (file_size < dcc->size)
2108 {
2109 dcc->resumable = file_size;
2110 dcc->pos = file_size;
2111 }
2112 else
2113 {
2114 dcc->resume_error = 2;
2115 }
2116
2117 g_object_unref (file_info);
2118 }
2119 else
2120 {
2121 dcc->resume_errno = errno;
2122 dcc->resume_error = 1;
2123 }
2124
2125 g_object_unref(file);
2126 }
2127 else
2128 {
2129 dcc->resume_errno = errno;
2130 dcc->resume_error = 1;
2131 }
2132 }
2133 else
2134 {
2135 dcc->resume_errno = errno;
2136 dcc->resume_error = 1;
2137 }
2138
2139 g_free (filename_fs);
2140
2141 /* Now verify that this DCC is not already in progress from someone else */
2142 if (dcc->resumable)
2143 {
2144 GSList *list = dcc_list;
2145 struct DCC *d;
2146 while (list)
2147 {
2148 d = list->data;
2149 if (d->type == TYPE_RECV && d->dccstat != STAT_ABORTED &&
2150 d->dccstat != STAT_DONE && d->dccstat != STAT_FAILED &&
2151 d->dccstat != STAT_QUEUED)
2152 {
2153 if (d != dcc && is_same_file (d, dcc))
2154 {
2155 dcc->resume_error = 3; /* dccgui.c uses it */
2156 dcc->resumable = 0;
2157 dcc->pos = 0;
2158 break;
2159 }
2160 }
2161 list = list->next;
2162 }
2163 }
2164 }
2165
2166 void
dcc_get(struct DCC * dcc)2167 dcc_get (struct DCC *dcc)
2168 {
2169 switch (dcc->dccstat)
2170 {
2171 case STAT_QUEUED:
2172 if (dcc->type != TYPE_CHATSEND)
2173 {
2174 if (dcc->type == TYPE_RECV && prefs.hex_dcc_auto_resume && dcc->resumable)
2175 {
2176 dcc_resume (dcc);
2177 }
2178 else
2179 {
2180 dcc->resumable = 0;
2181 dcc->pos = 0;
2182 dcc_connect (dcc);
2183 }
2184 }
2185 break;
2186 case STAT_DONE:
2187 case STAT_FAILED:
2188 case STAT_ABORTED:
2189 dcc_close (dcc, 0, TRUE);
2190 break;
2191 default:
2192 break;
2193 }
2194 }
2195
2196 /* for "Save As..." dialog */
2197
2198 void
dcc_get_with_destfile(struct DCC * dcc,char * file)2199 dcc_get_with_destfile (struct DCC *dcc, char *file)
2200 {
2201 g_free (dcc->destfile);
2202 dcc->destfile = g_strdup (file); /* utf-8 */
2203
2204 /* since destfile changed, must check resumability again */
2205 update_is_resumable (dcc);
2206
2207 dcc_get (dcc);
2208 }
2209
2210 void
dcc_get_nick(struct session * sess,char * nick)2211 dcc_get_nick (struct session *sess, char *nick)
2212 {
2213 struct DCC *dcc;
2214 GSList *list = dcc_list;
2215 while (list)
2216 {
2217 dcc = (struct DCC *) list->data;
2218 if (!sess->server->p_cmp (nick, dcc->nick))
2219 {
2220 if (dcc->dccstat == STAT_QUEUED && dcc->type == TYPE_RECV)
2221 {
2222 update_is_resumable (dcc);
2223 if (prefs.hex_dcc_auto_resume && dcc->resumable)
2224 {
2225 dcc_resume (dcc);
2226 }
2227 else
2228 {
2229 dcc->pos = 0;
2230 dcc->ack = 0;
2231 dcc_connect (dcc);
2232 }
2233 return;
2234 }
2235 }
2236 list = list->next;
2237 }
2238 if (sess)
2239 EMIT_SIGNAL (XP_TE_DCCIVAL, sess, NULL, NULL, NULL, NULL, 0);
2240 }
2241
2242 static struct DCC *
new_dcc(void)2243 new_dcc (void)
2244 {
2245 struct DCC *dcc = g_new0 (struct DCC, 1);
2246 dcc->sok = -1;
2247 dcc->fp = -1;
2248 dcc_list = g_slist_prepend (dcc_list, dcc);
2249 if (timeout_timer == 0)
2250 {
2251 timeout_timer = fe_timeout_add_seconds (1, dcc_check_timeouts, NULL);
2252 }
2253 return dcc;
2254 }
2255
2256 void
dcc_chat(struct session * sess,char * nick,int passive)2257 dcc_chat (struct session *sess, char *nick, int passive)
2258 {
2259 char outbuf[512];
2260 struct DCC *dcc;
2261
2262 dcc = find_dcc (nick, "", TYPE_CHATSEND);
2263 if (dcc)
2264 {
2265 switch (dcc->dccstat)
2266 {
2267 case STAT_ACTIVE:
2268 case STAT_QUEUED:
2269 case STAT_CONNECTING:
2270 EMIT_SIGNAL (XP_TE_DCCCHATREOFFER, sess, nick, NULL, NULL, NULL, 0);
2271 return;
2272 case STAT_ABORTED:
2273 case STAT_FAILED:
2274 dcc_close (dcc, 0, TRUE);
2275 break;
2276 case STAT_DONE:
2277 break;
2278 }
2279 }
2280 dcc = find_dcc (nick, "", TYPE_CHATRECV);
2281 if (dcc)
2282 {
2283 switch (dcc->dccstat)
2284 {
2285 case STAT_QUEUED:
2286 dcc_connect (dcc);
2287 break;
2288 case STAT_FAILED:
2289 case STAT_ABORTED:
2290 dcc_close (dcc, 0, TRUE);
2291 break;
2292 default:
2293 break;
2294 }
2295 return;
2296 }
2297 /* offer DCC CHAT */
2298
2299 dcc = new_dcc ();
2300 if (!dcc)
2301 return;
2302 dcc->starttime = dcc->offertime = time (0);
2303 dcc->serv = sess->server;
2304 dcc->dccstat = STAT_QUEUED;
2305 dcc->type = TYPE_CHATSEND;
2306 dcc->nick = g_strdup (nick);
2307 if (passive || dcc_listen_init (dcc, sess))
2308 {
2309 if (prefs.hex_gui_autoopen_chat)
2310 {
2311 if (fe_dcc_open_chat_win (TRUE)) /* already open? add only */
2312 fe_dcc_add (dcc);
2313 } else
2314 fe_dcc_add (dcc);
2315
2316 if (passive)
2317 {
2318 dcc->pasvid = new_id ();
2319 g_snprintf (outbuf, sizeof (outbuf), "DCC CHAT chat 199 %d %d",
2320 dcc->port, dcc->pasvid);
2321 } else
2322 {
2323 g_snprintf (outbuf, sizeof (outbuf), "DCC CHAT chat %u %d",
2324 dcc->addr, dcc->port);
2325 }
2326 dcc->serv->p_ctcp (dcc->serv, nick, outbuf);
2327 EMIT_SIGNAL (XP_TE_DCCCHATOFFERING, sess, nick, NULL, NULL, NULL, 0);
2328 } else
2329 {
2330 dcc_close (dcc, 0, TRUE);
2331 }
2332 }
2333
2334 static void
dcc_malformed(struct session * sess,char * nick,char * data)2335 dcc_malformed (struct session *sess, char *nick, char *data)
2336 {
2337 EMIT_SIGNAL (XP_TE_MALFORMED, sess, nick, data, NULL, NULL, 0);
2338 }
2339
2340 int
dcc_resume(struct DCC * dcc)2341 dcc_resume (struct DCC *dcc)
2342 {
2343 char tbuf[500];
2344
2345 update_is_resumable (dcc);
2346
2347 if (dcc->dccstat == STAT_QUEUED && dcc->resumable)
2348 {
2349 dcc->resume_sent = 1;
2350 /* filename contains spaces? Quote them! */
2351 g_snprintf (tbuf, sizeof (tbuf) - 10, strchr (dcc->file, ' ') ?
2352 "DCC RESUME \"%s\" %d %" G_GUINT64_FORMAT :
2353 "DCC RESUME %s %d %" G_GUINT64_FORMAT,
2354 dcc->file, dcc->port, dcc->resumable);
2355
2356 if (dcc->pasvid)
2357 sprintf (tbuf + strlen (tbuf), " %d", dcc->pasvid);
2358
2359 dcc->serv->p_ctcp (dcc->serv, dcc->nick, tbuf);
2360 return 1;
2361 }
2362
2363 return 0;
2364 }
2365
2366 static void
dcc_confirm_send(void * ud)2367 dcc_confirm_send (void *ud)
2368 {
2369 struct DCC *dcc = (struct DCC *) ud;
2370 dcc_get (dcc);
2371 }
2372
2373 static void
dcc_deny_send(void * ud)2374 dcc_deny_send (void *ud)
2375 {
2376 struct DCC *dcc = (struct DCC *) ud;
2377 dcc_abort (dcc->serv->front_session, dcc);
2378 }
2379
2380 static void
dcc_confirm_chat(void * ud)2381 dcc_confirm_chat (void *ud)
2382 {
2383 struct DCC *dcc = (struct DCC *) ud;
2384 dcc_connect (dcc);
2385 }
2386
2387 static void
dcc_deny_chat(void * ud)2388 dcc_deny_chat (void *ud)
2389 {
2390 struct DCC *dcc = (struct DCC *) ud;
2391 dcc_abort (dcc->serv->front_session, dcc);
2392 }
2393
2394 static struct DCC *
dcc_add_chat(session * sess,char * nick,int port,guint32 addr,int pasvid)2395 dcc_add_chat (session *sess, char *nick, int port, guint32 addr, int pasvid)
2396 {
2397 struct DCC *dcc;
2398
2399 dcc = new_dcc ();
2400 if (dcc)
2401 {
2402 dcc->serv = sess->server;
2403 dcc->type = TYPE_CHATRECV;
2404 dcc->dccstat = STAT_QUEUED;
2405 dcc->addr = addr;
2406 dcc->port = port;
2407 dcc->pasvid = pasvid;
2408 dcc->nick = g_strdup (nick);
2409 dcc->starttime = time (0);
2410
2411 EMIT_SIGNAL (XP_TE_DCCCHATOFFER, sess->server->front_session, nick,
2412 NULL, NULL, NULL, 0);
2413
2414 if (prefs.hex_gui_autoopen_chat)
2415 {
2416 if (fe_dcc_open_chat_win (TRUE)) /* already open? add only */
2417 fe_dcc_add (dcc);
2418 } else
2419 fe_dcc_add (dcc);
2420
2421 if (prefs.hex_dcc_auto_chat)
2422 {
2423 dcc_connect (dcc);
2424 }
2425 else
2426 {
2427 char buff[128];
2428 g_snprintf (buff, sizeof (buff), "%s is offering DCC Chat. Do you want to accept?", nick);
2429 fe_confirm (buff, dcc_confirm_chat, dcc_deny_chat, dcc);
2430 }
2431 }
2432
2433 return dcc;
2434 }
2435
2436 static struct DCC *
dcc_add_file(session * sess,char * file,guint64 size,int port,char * nick,guint32 addr,int pasvid)2437 dcc_add_file (session *sess, char *file, guint64 size, int port, char *nick, guint32 addr, int pasvid)
2438 {
2439 struct DCC *dcc;
2440 char tbuf[512];
2441
2442 dcc = new_dcc ();
2443 if (dcc)
2444 {
2445 dcc->file = g_strdup (file);
2446
2447 dcc->destfile = g_malloc (strlen (prefs.hex_dcc_dir) + strlen (nick) +
2448 strlen (file) + 4);
2449
2450 strcpy (dcc->destfile, prefs.hex_dcc_dir);
2451 if (prefs.hex_dcc_dir[strlen (prefs.hex_dcc_dir) - 1] != G_DIR_SEPARATOR)
2452 strcat (dcc->destfile, G_DIR_SEPARATOR_S);
2453 if (prefs.hex_dcc_save_nick)
2454 {
2455 #ifdef WIN32
2456 char *t = strlen (dcc->destfile) + dcc->destfile;
2457 strcpy (t, nick);
2458 while (*t)
2459 {
2460 if (*t == '\\' || *t == '|')
2461 *t = '_';
2462 t++;
2463 }
2464 #else
2465 strcat (dcc->destfile, nick);
2466 #endif
2467 strcat (dcc->destfile, ".");
2468 }
2469 strcat (dcc->destfile, file);
2470
2471 dcc->resumable = 0;
2472 dcc->pos = 0;
2473 dcc->serv = sess->server;
2474 dcc->type = TYPE_RECV;
2475 dcc->dccstat = STAT_QUEUED;
2476 dcc->addr = addr;
2477 dcc->port = port;
2478 dcc->pasvid = pasvid;
2479 dcc->size = size;
2480 dcc->nick = g_strdup (nick);
2481 dcc->maxcps = prefs.hex_dcc_max_get_cps;
2482
2483 update_is_resumable (dcc);
2484
2485 if (prefs.hex_dcc_auto_recv == 1)
2486 {
2487 g_snprintf (tbuf, sizeof (tbuf), _("%s is offering \"%s\". Do you want to accept?"), nick, file);
2488 fe_confirm (tbuf, dcc_confirm_send, dcc_deny_send, dcc);
2489 }
2490 else if (prefs.hex_dcc_auto_recv == 2)
2491 {
2492 dcc_get (dcc);
2493 }
2494 if (prefs.hex_gui_autoopen_recv)
2495 {
2496 if (fe_dcc_open_recv_win (TRUE)) /* was already open? just add*/
2497 fe_dcc_add (dcc);
2498 } else
2499 fe_dcc_add (dcc);
2500 }
2501 sprintf (tbuf, "%" G_GUINT64_FORMAT, size);
2502 g_snprintf (tbuf + 24, 300, "%s:%d", net_ip (addr), port);
2503 EMIT_SIGNAL (XP_TE_DCCSENDOFFER, sess->server->front_session, nick,
2504 file, tbuf, tbuf + 24, 0);
2505
2506 return dcc;
2507 }
2508
2509 void
handle_dcc(struct session * sess,char * nick,char * word[],char * word_eol[],const message_tags_data * tags_data)2510 handle_dcc (struct session *sess, char *nick, char *word[], char *word_eol[],
2511 const message_tags_data *tags_data)
2512 {
2513 char tbuf[512];
2514 struct DCC *dcc;
2515 char *type = word[5];
2516 int port, pasvid = 0;
2517 guint32 addr;
2518 guint64 size;
2519 int psend = 0;
2520
2521 if (!g_ascii_strcasecmp (type, "CHAT"))
2522 {
2523 port = atoi (word[8]);
2524 addr = strtoul (word[7], NULL, 10);
2525
2526 if (port == 0)
2527 pasvid = atoi (word[9]);
2528 else if (word[9][0] != 0)
2529 {
2530 pasvid = atoi (word[9]);
2531 psend = 1;
2532 }
2533
2534 if (!addr /*|| (port < 1024 && port != 0)*/
2535 || port > 0xffff || (port == 0 && pasvid == 0))
2536 {
2537 dcc_malformed (sess, nick, word_eol[4] + 2);
2538 return;
2539 }
2540
2541 if (psend)
2542 {
2543 dcc = find_dcc_from_id (pasvid, TYPE_CHATSEND);
2544 if (dcc)
2545 {
2546 dcc->addr = addr;
2547 dcc->port = port;
2548 dcc_connect (dcc);
2549 } else
2550 {
2551 dcc_malformed (sess, nick, word_eol[4] + 2);
2552 }
2553 return;
2554 }
2555
2556 dcc = find_dcc (nick, "", TYPE_CHATSEND);
2557 if (dcc)
2558 dcc_close (dcc, 0, TRUE);
2559
2560 dcc = find_dcc (nick, "", TYPE_CHATRECV);
2561 if (dcc)
2562 dcc_close (dcc, 0, TRUE);
2563
2564 dcc_add_chat (sess, nick, port, addr, pasvid);
2565 return;
2566 }
2567
2568 if (!g_ascii_strcasecmp (type, "Resume"))
2569 {
2570 port = atoi (word[7]);
2571
2572 if (port == 0)
2573 { /* PASSIVE */
2574 pasvid = atoi(word[9]);
2575 dcc = find_dcc_from_id(pasvid, TYPE_SEND);
2576 } else
2577 {
2578 dcc = find_dcc_from_port (port, TYPE_SEND);
2579 }
2580 if (!dcc)
2581 dcc = find_dcc (nick, word[6], TYPE_SEND);
2582 if (dcc)
2583 {
2584 size = g_ascii_strtoull (word[8], NULL, 10);
2585 dcc->resumable = size;
2586 if (dcc->resumable < dcc->size)
2587 {
2588 dcc->pos = dcc->resumable;
2589 dcc->ack = dcc->resumable;
2590 lseek (dcc->fp, dcc->pos, SEEK_SET);
2591
2592 /* Checking if dcc is passive and if filename contains spaces */
2593 if (dcc->pasvid)
2594 g_snprintf (tbuf, sizeof (tbuf), strchr (file_part (dcc->file), ' ') ?
2595 "DCC ACCEPT \"%s\" %d %" G_GUINT64_FORMAT " %d" :
2596 "DCC ACCEPT %s %d %" G_GUINT64_FORMAT " %d",
2597 file_part (dcc->file), port, dcc->resumable, dcc->pasvid);
2598 else
2599 g_snprintf (tbuf, sizeof (tbuf), strchr (file_part (dcc->file), ' ') ?
2600 "DCC ACCEPT \"%s\" %d %" G_GUINT64_FORMAT :
2601 "DCC ACCEPT %s %d %" G_GUINT64_FORMAT,
2602 file_part (dcc->file), port, dcc->resumable);
2603
2604 dcc->serv->p_ctcp (dcc->serv, dcc->nick, tbuf);
2605 }
2606 sprintf (tbuf, "%" G_GUINT64_FORMAT, dcc->pos);
2607 EMIT_SIGNAL_TIMESTAMP (XP_TE_DCCRESUMEREQUEST, sess, nick,
2608 file_part (dcc->file), tbuf, NULL, 0,
2609 tags_data->timestamp);
2610 }
2611 return;
2612 }
2613 if (!g_ascii_strcasecmp (type, "Accept"))
2614 {
2615 port = atoi (word[7]);
2616 dcc = find_dcc_from_port (port, TYPE_RECV);
2617 if (dcc && dcc->dccstat == STAT_QUEUED)
2618 {
2619 dcc_connect (dcc);
2620 }
2621 return;
2622 }
2623 if (!g_ascii_strcasecmp (type, "SEND"))
2624 {
2625 char *file = file_part (word[6]);
2626
2627 port = atoi (word[8]);
2628 addr = strtoul (word[7], NULL, 10);
2629 size = g_ascii_strtoull (word[9], NULL, 10);
2630
2631 if (port == 0) /* Passive dcc requested */
2632 pasvid = atoi (word[10]);
2633 else if (word[10][0] != 0)
2634 {
2635 /* Requesting passive dcc.
2636 * Destination user of an active dcc is giving his
2637 * TRUE address/port/pasvid data.
2638 * This information will be used later to
2639 * establish the connection to the user.
2640 * We can recognize this type of dcc using word[10]
2641 * because this field is always null (no pasvid)
2642 * in normal dcc sends.
2643 */
2644 pasvid = atoi (word[10]);
2645 psend = 1;
2646 }
2647
2648
2649 if (!addr || !size /*|| (port < 1024 && port != 0)*/
2650 || port > 0xffff || (port == 0 && pasvid == 0))
2651 {
2652 dcc_malformed (sess, nick, word_eol[4] + 2);
2653 return;
2654 }
2655
2656 if (psend)
2657 {
2658 /* Third Step of Passive send.
2659 * Connecting to the destination and finally
2660 * sending file.
2661 */
2662 dcc = find_dcc_from_id (pasvid, TYPE_SEND);
2663 if (dcc)
2664 {
2665 dcc->addr = addr;
2666 dcc->port = port;
2667 dcc_connect (dcc);
2668 } else
2669 {
2670 dcc_malformed (sess, nick, word_eol[4] + 2);
2671 }
2672 return;
2673 }
2674
2675 dcc_add_file (sess, file, size, port, nick, addr, pasvid);
2676
2677 } else
2678 {
2679 EMIT_SIGNAL_TIMESTAMP (XP_TE_DCCGENERICOFFER, sess->server->front_session,
2680 word_eol[4] + 2, nick, NULL, NULL, 0,
2681 tags_data->timestamp);
2682 }
2683 }
2684
2685 void
dcc_show_list(struct session * sess)2686 dcc_show_list (struct session *sess)
2687 {
2688 int i = 0;
2689 struct DCC *dcc;
2690 GSList *list = dcc_list;
2691
2692 EMIT_SIGNAL (XP_TE_DCCHEAD, sess, NULL, NULL, NULL, NULL, 0);
2693 while (list)
2694 {
2695 dcc = (struct DCC *) list->data;
2696 i++;
2697 PrintTextf (sess, " %s %-10.10s %-7.7s %-7" G_GUINT64_FORMAT " %-7" G_GUINT64_FORMAT " %s\n",
2698 dcctypes[dcc->type], dcc->nick,
2699 _(dccstat[dcc->dccstat].name), dcc->size, dcc->pos,
2700 file_part (dcc->file));
2701 list = list->next;
2702 }
2703 if (!i)
2704 PrintText (sess, _("No active DCCs\n"));
2705 }
2706