2011-02-23 22:14:30 -05:00
|
|
|
/* X-Chat
|
|
|
|
* Copyright (C) 1998-2006 Peter Zelezny.
|
|
|
|
* Copyright (C) 2006 Damjan Jovanovic
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
2012-12-23 14:36:54 -05:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
2011-02-23 22:14:30 -05:00
|
|
|
*
|
|
|
|
* Wayne Conrad, 3 Apr 1999: Color-coded DCC file transfer status windows
|
|
|
|
* Bernhard Valenti <bernhard.valenti@gmx.net> 2000-11-21: Fixed DCC send behind nat
|
|
|
|
*
|
|
|
|
* 2001-03-08 Added support for getting "dcc_ip" config parameter.
|
|
|
|
* Jim Seymour (jseymour@LinxNet.com)
|
|
|
|
*/
|
|
|
|
|
2014-12-06 17:02:45 -05:00
|
|
|
/* Required to make lseek use off64_t, but doesn't work on Windows */
|
2011-02-23 22:14:30 -05:00
|
|
|
#define _FILE_OFFSET_BITS 64
|
2014-12-06 17:02:45 -05:00
|
|
|
|
2011-02-23 22:14:30 -05:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
#define WANTSOCKET
|
|
|
|
#define WANTARPA
|
|
|
|
#define WANTDNS
|
|
|
|
#include "inet.h"
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
#include <windows.h>
|
2012-07-21 08:26:19 -04:00
|
|
|
#include <io.h>
|
2011-12-11 11:34:02 -05:00
|
|
|
#else
|
|
|
|
#include <unistd.h>
|
2011-02-23 22:14:30 -05:00
|
|
|
#endif
|
|
|
|
|
2012-10-24 15:33:02 -04:00
|
|
|
#include "hexchat.h"
|
2011-02-23 22:14:30 -05:00
|
|
|
#include "util.h"
|
|
|
|
#include "fe.h"
|
|
|
|
#include "outbound.h"
|
|
|
|
#include "inbound.h"
|
|
|
|
#include "network.h"
|
|
|
|
#include "plugin.h"
|
|
|
|
#include "server.h"
|
|
|
|
#include "text.h"
|
|
|
|
#include "url.h"
|
2012-10-24 15:33:02 -04:00
|
|
|
#include "hexchatc.h"
|
2011-02-23 22:14:30 -05:00
|
|
|
|
2014-12-06 17:02:45 -05:00
|
|
|
/* Setting _FILE_OFFSET_BITS to 64 doesn't change lseek to use off64_t on Windows, so override lseek to the version that does */
|
2011-12-11 11:34:02 -05:00
|
|
|
#ifdef WIN32
|
2014-12-06 17:02:45 -05:00
|
|
|
#define lseek _lseeki64
|
2011-02-23 22:14:30 -05:00
|
|
|
#endif
|
|
|
|
|
|
|
|
static char *dcctypes[] = { "SEND", "RECV", "CHAT", "CHAT" };
|
|
|
|
|
|
|
|
struct dccstat_info dccstat[] = {
|
|
|
|
{N_("Waiting"), 1 /*black */ },
|
|
|
|
{N_("Active"), 12 /*cyan */ },
|
|
|
|
{N_("Failed"), 4 /*red */ },
|
|
|
|
{N_("Done"), 3 /*green */ },
|
|
|
|
{N_("Connect"), 1 /*black */ },
|
|
|
|
{N_("Aborted"), 4 /*red */ },
|
|
|
|
};
|
|
|
|
|
|
|
|
static int dcc_global_throttle; /* 0x1 = sends, 0x2 = gets */
|
2014-12-06 17:02:45 -05:00
|
|
|
static gint64 dcc_sendcpssum, dcc_getcpssum;
|
2011-02-23 22:14:30 -05:00
|
|
|
|
|
|
|
static struct DCC *new_dcc (void);
|
|
|
|
static void dcc_close (struct DCC *dcc, int dccstat, int destroy);
|
|
|
|
static gboolean dcc_send_data (GIOChannel *, GIOCondition, struct DCC *);
|
|
|
|
static gboolean dcc_read (GIOChannel *, GIOCondition, struct DCC *);
|
|
|
|
static gboolean dcc_read_ack (GIOChannel *source, GIOCondition condition, struct DCC *dcc);
|
|
|
|
|
|
|
|
static int new_id()
|
|
|
|
{
|
|
|
|
static int id = 0;
|
|
|
|
if (id == 0)
|
|
|
|
{
|
|
|
|
/* start the first ID at a random number for pseudo security */
|
|
|
|
/* 1 - 255 */
|
|
|
|
id = RAND_INT(255) + 1;
|
|
|
|
/* ignore overflows, since it can go to 2 billion */
|
|
|
|
}
|
|
|
|
return id++;
|
|
|
|
}
|
|
|
|
|
|
|
|
static double
|
|
|
|
timeval_diff (GTimeVal *greater,
|
|
|
|
GTimeVal *less)
|
|
|
|
{
|
|
|
|
long usecdiff;
|
|
|
|
double result;
|
|
|
|
|
|
|
|
result = greater->tv_sec - less->tv_sec;
|
|
|
|
usecdiff = (long) greater->tv_usec - less->tv_usec;
|
|
|
|
result += (double) usecdiff / 1000000;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dcc_unthrottle (struct DCC *dcc)
|
|
|
|
{
|
|
|
|
/* don't unthrottle here, but delegate to funcs */
|
|
|
|
if (dcc->type == TYPE_RECV)
|
|
|
|
dcc_read (NULL, 0, dcc);
|
|
|
|
else
|
|
|
|
dcc_send_data (NULL, 0, dcc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dcc_calc_cps (struct DCC *dcc)
|
|
|
|
{
|
|
|
|
GTimeVal now;
|
2014-12-06 17:02:45 -05:00
|
|
|
gint64 oldcps;
|
2011-02-23 22:14:30 -05:00
|
|
|
double timediff, startdiff;
|
|
|
|
int glob_throttle_bit, wasthrottled;
|
2014-12-06 17:02:45 -05:00
|
|
|
gint64 *cpssum;
|
|
|
|
int glob_limit;
|
|
|
|
goffset pos, posdiff;
|
2011-02-23 22:14:30 -05:00
|
|
|
|
|
|
|
g_get_current_time (&now);
|
|
|
|
|
|
|
|
/* the pos we use for sends is an average
|
|
|
|
between pos and ack */
|
|
|
|
if (dcc->type == TYPE_SEND)
|
|
|
|
{
|
|
|
|
/* carefull to avoid 32bit overflow */
|
|
|
|
pos = dcc->pos - ((dcc->pos - dcc->ack) / 2);
|
|
|
|
glob_throttle_bit = 0x1;
|
|
|
|
cpssum = &dcc_sendcpssum;
|
2012-10-22 06:10:55 -04:00
|
|
|
glob_limit = prefs.hex_dcc_global_max_send_cps;
|
2011-02-23 22:14:30 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pos = dcc->pos;
|
|
|
|
glob_throttle_bit = 0x2;
|
|
|
|
cpssum = &dcc_getcpssum;
|
2012-10-22 06:10:55 -04:00
|
|
|
glob_limit = prefs.hex_dcc_global_max_get_cps;
|
2011-02-23 22:14:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!dcc->firstcpstv.tv_sec && !dcc->firstcpstv.tv_usec)
|
|
|
|
dcc->firstcpstv = now;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
startdiff = timeval_diff (&now, &dcc->firstcpstv);
|
|
|
|
if (startdiff < 1)
|
|
|
|
startdiff = 1;
|
|
|
|
else if (startdiff > CPS_AVG_WINDOW)
|
|
|
|
startdiff = CPS_AVG_WINDOW;
|
|
|
|
|
|
|
|
timediff = timeval_diff (&now, &dcc->lastcpstv);
|
|
|
|
if (timediff > startdiff)
|
|
|
|
timediff = startdiff = 1;
|
|
|
|
|
|
|
|
posdiff = pos - dcc->lastcpspos;
|
|
|
|
oldcps = dcc->cps;
|
2014-12-06 17:02:45 -05:00
|
|
|
dcc->cps = (gint64) ((posdiff / timediff) * (timediff / startdiff) + dcc->cps * (1.0 - (timediff / startdiff)));
|
2011-02-23 22:14:30 -05:00
|
|
|
|
|
|
|
*cpssum += dcc->cps - oldcps;
|
|
|
|
}
|
|
|
|
|
|
|
|
dcc->lastcpspos = pos;
|
|
|
|
dcc->lastcpstv = now;
|
|
|
|
|
|
|
|
/* now check cps against set limits... */
|
|
|
|
wasthrottled = dcc->throttled;
|
|
|
|
|
|
|
|
/* check global limits first */
|
|
|
|
dcc->throttled &= ~0x2;
|
|
|
|
if (glob_limit > 0 && *cpssum >= glob_limit)
|
|
|
|
{
|
|
|
|
dcc_global_throttle |= glob_throttle_bit;
|
|
|
|
if (dcc->maxcps >= 0)
|
|
|
|
dcc->throttled |= 0x2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
dcc_global_throttle &= ~glob_throttle_bit;
|
|
|
|
|
|
|
|
/* now check per-connection limit */
|
|
|
|
if (dcc->maxcps > 0 && dcc->cps > dcc->maxcps)
|
|
|
|
dcc->throttled |= 0x1;
|
|
|
|
else
|
|
|
|
dcc->throttled &= ~0x1;
|
|
|
|
|
|
|
|
/* take action */
|
|
|
|
if (wasthrottled && !dcc->throttled)
|
|
|
|
dcc_unthrottle (dcc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dcc_remove_from_sum (struct DCC *dcc)
|
|
|
|
{
|
|
|
|
if (dcc->dccstat != STAT_ACTIVE)
|
|
|
|
return;
|
|
|
|
if (dcc->type == TYPE_SEND)
|
|
|
|
dcc_sendcpssum -= dcc->cps;
|
|
|
|
else if (dcc->type == TYPE_RECV)
|
|
|
|
dcc_getcpssum -= dcc->cps;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
is_dcc (struct DCC *dcc)
|
|
|
|
{
|
|
|
|
GSList *list = dcc_list;
|
|
|
|
while (list)
|
|
|
|
{
|
|
|
|
if (list->data == dcc)
|
|
|
|
return TRUE;
|
|
|
|
list = list->next;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2013-07-10 13:29:10 -04:00
|
|
|
gboolean
|
2013-07-17 04:20:54 -04:00
|
|
|
is_dcc_completed (struct DCC *dcc)
|
2013-07-10 13:29:10 -04:00
|
|
|
{
|
|
|
|
if (dcc != NULL)
|
|
|
|
return (dcc->dccstat == STAT_FAILED || dcc->dccstat == STAT_DONE || dcc->dccstat == STAT_ABORTED);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2012-10-30 06:35:39 -04:00
|
|
|
/* this is called from hexchat.c:hexchat_misc_checks() every 1 second. */
|
2011-02-23 22:14:30 -05:00
|
|
|
|
|
|
|
void
|
|
|
|
dcc_check_timeouts (void)
|
|
|
|
{
|
|
|
|
struct DCC *dcc;
|
|
|
|
time_t tim = time (0);
|
|
|
|
GSList *next, *list = dcc_list;
|
|
|
|
|
|
|
|
while (list)
|
|
|
|
{
|
|
|
|
dcc = (struct DCC *) list->data;
|
|
|
|
next = list->next;
|
|
|
|
|
|
|
|
switch (dcc->dccstat)
|
|
|
|
{
|
|
|
|
case STAT_ACTIVE:
|
|
|
|
dcc_calc_cps (dcc);
|
|
|
|
fe_dcc_update (dcc);
|
|
|
|
|
|
|
|
if (dcc->type == TYPE_SEND || dcc->type == TYPE_RECV)
|
|
|
|
{
|
2012-10-22 06:10:55 -04:00
|
|
|
if (prefs.hex_dcc_stall_timeout > 0)
|
2011-02-23 22:14:30 -05:00
|
|
|
{
|
|
|
|
if (!dcc->throttled
|
2012-10-22 06:10:55 -04:00
|
|
|
&& tim - dcc->lasttime > prefs.hex_dcc_stall_timeout)
|
2011-02-23 22:14:30 -05:00
|
|
|
{
|
|
|
|
EMIT_SIGNAL (XP_TE_DCCSTALL, dcc->serv->front_session,
|
|
|
|
dcctypes[dcc->type],
|
|
|
|
file_part (dcc->file), dcc->nick, NULL, 0);
|
|
|
|
dcc_close (dcc, STAT_ABORTED, FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case STAT_QUEUED:
|
|
|
|
if (dcc->type == TYPE_SEND || dcc->type == TYPE_CHATSEND)
|
|
|
|
{
|
2012-10-22 06:10:55 -04:00
|
|
|
if (tim - dcc->offertime > prefs.hex_dcc_timeout)
|
2011-02-23 22:14:30 -05:00
|
|
|
{
|
2012-10-22 06:10:55 -04:00
|
|
|
if (prefs.hex_dcc_timeout > 0)
|
2011-02-23 22:14:30 -05:00
|
|
|
{
|
|
|
|
EMIT_SIGNAL (XP_TE_DCCTOUT, dcc->serv->front_session,
|
|
|
|
dcctypes[dcc->type],
|
|
|
|
file_part (dcc->file), dcc->nick, NULL, 0);
|
|
|
|
dcc_close (dcc, STAT_ABORTED, FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case STAT_DONE:
|
|
|
|
case STAT_FAILED:
|
|
|
|
case STAT_ABORTED:
|
2012-10-22 06:10:55 -04:00
|
|
|
if (prefs.hex_dcc_remove)
|
2011-02-23 22:14:30 -05:00
|
|
|
dcc_close (dcc, 0, TRUE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
list = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
dcc_lookup_proxy (char *host, struct sockaddr_in *addr)
|
|
|
|
{
|
|
|
|
struct hostent *h;
|
|
|
|
static char *cache_host = NULL;
|
|
|
|
static guint32 cache_addr;
|
|
|
|
|
|
|
|
/* too lazy to thread this, so we cache results */
|
|
|
|
if (cache_host)
|
|
|
|
{
|
|
|
|
if (strcmp (host, cache_host) == 0)
|
|
|
|
{
|
|
|
|
memcpy (&addr->sin_addr, &cache_addr, 4);
|
|
|
|
return TRUE;
|
|
|
|
}
|
2014-12-28 06:37:25 -05:00
|
|
|
g_free (cache_host);
|
2011-02-23 22:14:30 -05:00
|
|
|
cache_host = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
h = gethostbyname (host);
|
|
|
|
if (h != NULL && h->h_length == 4 && h->h_addr_list[0] != NULL)
|
|
|
|
{
|
|
|
|
memcpy (&addr->sin_addr, h->h_addr, 4);
|
|
|
|
memcpy (&cache_addr, h->h_addr, 4);
|
2014-12-28 06:37:25 -05:00
|
|
|
cache_host = g_strdup (host);
|
2013-01-09 17:37:57 -05:00
|
|
|
/* cppcheck-suppress memleak */
|
2011-02-23 22:14:30 -05:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2012-10-22 09:55:43 -04:00
|
|
|
#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)
|
2011-02-23 22:14:30 -05:00
|
|
|
|
|
|
|
static int
|
|
|
|
dcc_connect_sok (struct DCC *dcc)
|
|
|
|
{
|
|
|
|
int sok;
|
|
|
|
struct sockaddr_in addr;
|
|
|
|
|
|
|
|
sok = socket (AF_INET, SOCK_STREAM, 0);
|
|
|
|
if (sok == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
memset (&addr, 0, sizeof (addr));
|
|
|
|
addr.sin_family = AF_INET;
|
|
|
|
if (DCC_USE_PROXY ())
|
|
|
|
{
|
2012-10-22 09:55:43 -04:00
|
|
|
if (!dcc_lookup_proxy (prefs.hex_net_proxy_host, &addr))
|
2011-02-23 22:14:30 -05:00
|
|
|
{
|
|
|
|
closesocket (sok);
|
|
|
|
return -1;
|
|
|
|
}
|
2012-10-22 09:55:43 -04:00
|
|
|
addr.sin_port = htons (prefs.hex_net_proxy_port);
|
2011-02-23 22:14:30 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
addr.sin_port = htons (dcc->port);
|
|
|
|
addr.sin_addr.s_addr = htonl (dcc->addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
set_nonblocking (sok);
|
|
|
|
connect (sok, (struct sockaddr *) &addr, sizeof (addr));
|
|
|
|
|
|
|
|
return sok;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dcc_close (struct DCC *dcc, int dccstat, int destroy)
|
|
|
|
{
|
|
|
|
if (dcc->wiotag)
|
|
|
|
{
|
|
|
|
fe_input_remove (dcc->wiotag);
|
|
|
|
dcc->wiotag = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dcc->iotag)
|
|
|
|
{
|
|
|
|
fe_input_remove (dcc->iotag);
|
|
|
|
dcc->iotag = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dcc->sok != -1)
|
|
|
|
{
|
|
|
|
closesocket (dcc->sok);
|
|
|
|
dcc->sok = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
dcc_remove_from_sum (dcc);
|
|
|
|
|
|
|
|
if (dcc->fp != -1)
|
|
|
|
{
|
|
|
|
close (dcc->fp);
|
|
|
|
dcc->fp = -1;
|
|
|
|
|
|
|
|
if(dccstat == STAT_DONE)
|
|
|
|
{
|
2013-10-05 12:26:55 -04:00
|
|
|
/* if we just completed a dcc receive, move the */
|
2011-02-23 22:14:30 -05:00
|
|
|
/* completed file to the completed directory */
|
|
|
|
if(dcc->type == TYPE_RECV)
|
|
|
|
{
|
2012-10-22 05:30:38 -04:00
|
|
|
/* mgl: change this to handle the case where dccwithnick is set */
|
2012-11-03 13:24:25 -04:00
|
|
|
move_file (prefs.hex_dcc_dir, prefs.hex_dcc_completed_dir,
|
2012-10-22 06:10:55 -04:00
|
|
|
file_part (dcc->destfile), prefs.hex_dcc_permissions);
|
2011-02-23 22:14:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dcc->dccstat = dccstat;
|
|
|
|
if (dcc->dccchat)
|
|
|
|
{
|
2014-12-28 06:37:25 -05:00
|
|
|
g_free (dcc->dccchat);
|
2011-02-23 22:14:30 -05:00
|
|
|
dcc->dccchat = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (destroy)
|
|
|
|
{
|
|
|
|
dcc_list = g_slist_remove (dcc_list, dcc);
|
|
|
|
fe_dcc_remove (dcc);
|
2014-12-09 00:24:59 -05:00
|
|
|
g_free (dcc->proxy);
|
|
|
|
g_free (dcc->file);
|
|
|
|
g_free (dcc->destfile);
|
2014-12-28 06:37:25 -05:00
|
|
|
g_free (dcc->nick);
|
2014-12-09 00:24:59 -05:00
|
|
|
g_free (dcc);
|
2011-02-23 22:14:30 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fe_dcc_update (dcc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dcc_abort (session *sess, struct DCC *dcc)
|
|
|
|
{
|
|
|
|
if (dcc)
|
|
|
|
{
|
|
|
|
switch (dcc->dccstat)
|
|
|
|
{
|
|
|
|
case STAT_QUEUED:
|
|
|
|
case STAT_CONNECTING:
|
|
|
|
case STAT_ACTIVE:
|
|
|
|
dcc_close (dcc, STAT_ABORTED, FALSE);
|
|
|
|
switch (dcc->type)
|
|
|
|
{
|
|
|
|
case TYPE_CHATSEND:
|
|
|
|
case TYPE_CHATRECV:
|
|
|
|
EMIT_SIGNAL (XP_TE_DCCCHATABORT, sess, dcc->nick, NULL, NULL,
|
|
|
|
NULL, 0);
|
|
|
|
break;
|
|
|
|
case TYPE_SEND:
|
|
|
|
EMIT_SIGNAL (XP_TE_DCCSENDABORT, sess, dcc->nick,
|
|
|
|
file_part (dcc->file), NULL, NULL, 0);
|
|
|
|
break;
|
|
|
|
case TYPE_RECV:
|
|
|
|
EMIT_SIGNAL (XP_TE_DCCRECVABORT, sess, dcc->nick,
|
|
|
|
dcc->file, NULL, NULL, 0);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
dcc_close (dcc, 0, TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dcc_notify_kill (struct server *serv)
|
|
|
|
{
|
|
|
|
struct server *replaceserv = 0;
|
|
|
|
struct DCC *dcc;
|
|
|
|
GSList *list = dcc_list;
|
|
|
|
if (serv_list)
|
|
|
|
replaceserv = (struct server *) serv_list->data;
|
|
|
|
while (list)
|
|
|
|
{
|
|
|
|
dcc = (struct DCC *) list->data;
|
|
|
|
if (dcc->serv == serv)
|
|
|
|
dcc->serv = replaceserv;
|
|
|
|
list = list->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct DCC *
|
|
|
|
dcc_write_chat (char *nick, char *text)
|
|
|
|
{
|
|
|
|
struct DCC *dcc;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
dcc = find_dcc (nick, "", TYPE_CHATRECV);
|
|
|
|
if (!dcc)
|
|
|
|
dcc = find_dcc (nick, "", TYPE_CHATSEND);
|
|
|
|
if (dcc && dcc->dccstat == STAT_ACTIVE)
|
|
|
|
{
|
|
|
|
len = strlen (text);
|
2015-01-31 03:52:31 -05:00
|
|
|
tcp_send_real (NULL, dcc->sok, dcc->serv->write_converter, text, len);
|
2011-02-23 22:14:30 -05:00
|
|
|
send (dcc->sok, "\n", 1, 0);
|
|
|
|
dcc->size += len;
|
|
|
|
fe_dcc_update (dcc);
|
|
|
|
return dcc;
|
|
|
|
}
|
2014-12-31 11:31:17 -05:00
|
|
|
return NULL;
|
2011-02-23 22:14:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* returns: 0 - ok
|
|
|
|
1 - the dcc is closed! */
|
|
|
|
|
|
|
|
static int
|
|
|
|
dcc_chat_line (struct DCC *dcc, char *line)
|
|
|
|
{
|
|
|
|
session *sess;
|
|
|
|
char *word[PDIWORDS];
|
|
|
|
char *po;
|
|
|
|
int ret, i;
|
|
|
|
char portbuf[32];
|
2013-06-22 11:55:41 -04:00
|
|
|
message_tags_data no_tags = MESSAGE_TAGS_DATA_INIT;
|
2011-02-23 22:14:30 -05:00
|
|
|
|
2015-01-31 03:52:31 -05:00
|
|
|
line = text_convert_invalid (line, -1, dcc->serv->read_converter, unicode_fallback_string, NULL);
|
2011-02-23 22:14:30 -05:00
|
|
|
|
|
|
|
sess = find_dialog (dcc->serv, dcc->nick);
|
|
|
|
if (!sess)
|
|
|
|
sess = dcc->serv->front_session;
|
|
|
|
|
|
|
|
sprintf (portbuf, "%d", dcc->port);
|
|
|
|
|
|
|
|
word[0] = "DCC Chat Text";
|
|
|
|
word[1] = net_ip (dcc->addr);
|
|
|
|
word[2] = portbuf;
|
|
|
|
word[3] = dcc->nick;
|
|
|
|
word[4] = line;
|
|
|
|
for (i = 5; i < PDIWORDS; i++)
|
|
|
|
word[i] = "\000";
|
|
|
|
|
2013-11-27 19:59:31 -05:00
|
|
|
ret = plugin_emit_print (sess, word, 0);
|
2011-02-23 22:14:30 -05:00
|
|
|
|
|
|
|
/* did the plugin close it? */
|
|
|
|
if (!g_slist_find (dcc_list, dcc))
|
|
|
|
{
|
2015-01-18 05:10:04 -05:00
|
|
|
g_free (line);
|
2011-02-23 22:14:30 -05:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* did the plugin eat the event? */
|
|
|
|
if (ret)
|
|
|
|
{
|
2015-01-18 05:10:04 -05:00
|
|
|
g_free (line);
|
2011-02-23 22:14:30 -05:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-15 13:25:28 -05:00
|
|
|
url_check_line (line);
|
2011-02-23 22:14:30 -05:00
|
|
|
|
2012-06-16 07:01:47 -04:00
|
|
|
if (line[0] == 1 && !g_ascii_strncasecmp (line + 1, "ACTION", 6))
|
2011-02-23 22:14:30 -05:00
|
|
|
{
|
|
|
|
po = strchr (line + 8, '\001');
|
|
|
|
if (po)
|
|
|
|
po[0] = 0;
|
2013-06-23 14:53:41 -04:00
|
|
|
inbound_action (sess, dcc->serv->nick, dcc->nick, "", line + 8, FALSE,
|
|
|
|
FALSE, &no_tags);
|
2011-02-23 22:14:30 -05:00
|
|
|
} else
|
|
|
|
{
|
2013-06-22 11:55:41 -04:00
|
|
|
inbound_privmsg (dcc->serv, dcc->nick, "", line, FALSE, &no_tags);
|
2011-02-23 22:14:30 -05:00
|
|
|
}
|
2015-01-18 05:10:04 -05:00
|
|
|
g_free (line);
|
2011-02-23 22:14:30 -05:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
dcc_read_chat (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
|
|
|
|
{
|
|
|
|
int i, len, dead;
|
|
|
|
char portbuf[32];
|
|
|
|
char lbuf[2050];
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
if (dcc->throttled)
|
|
|
|
{
|
|
|
|
fe_input_remove (dcc->iotag);
|
|
|
|
dcc->iotag = 0;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!dcc->iotag)
|
|
|
|
dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX, dcc_read_chat, dcc);
|
|
|
|
|
|
|
|
len = recv (dcc->sok, lbuf, sizeof (lbuf) - 2, 0);
|
|
|
|
if (len < 1)
|
|
|
|
{
|
|
|
|
if (len < 0)
|
|
|
|
{
|
|
|
|
if (would_block ())
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
sprintf (portbuf, "%d", dcc->port);
|
|
|
|
EMIT_SIGNAL (XP_TE_DCCCHATF, dcc->serv->front_session, dcc->nick,
|
|
|
|
net_ip (dcc->addr), portbuf,
|
|
|
|
errorstring ((len < 0) ? sock_error () : 0), 0);
|
|
|
|
dcc_close (dcc, STAT_FAILED, FALSE);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
i = 0;
|
|
|
|
lbuf[len] = 0;
|
|
|
|
while (i < len)
|
|
|
|
{
|
|
|
|
switch (lbuf[i])
|
|
|
|
{
|
|
|
|
case '\r':
|
|
|
|
break;
|
|
|
|
case '\n':
|
|
|
|
dcc->dccchat->linebuf[dcc->dccchat->pos] = 0;
|
|
|
|
dead = dcc_chat_line (dcc, dcc->dccchat->linebuf);
|
|
|
|
|
|
|
|
if (dead || !dcc->dccchat) /* the dcc has been closed, don't use (DCC *)! */
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
dcc->pos += dcc->dccchat->pos;
|
|
|
|
dcc->dccchat->pos = 0;
|
|
|
|
fe_dcc_update (dcc);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
dcc->dccchat->linebuf[dcc->dccchat->pos] = lbuf[i];
|
|
|
|
if (dcc->dccchat->pos < (sizeof (dcc->dccchat->linebuf) - 1))
|
|
|
|
dcc->dccchat->pos++;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dcc_calc_average_cps (struct DCC *dcc)
|
|
|
|
{
|
|
|
|
time_t sec;
|
|
|
|
|
|
|
|
sec = time (0) - dcc->starttime;
|
|
|
|
if (sec < 1)
|
|
|
|
sec = 1;
|
|
|
|
if (dcc->type == TYPE_SEND)
|
|
|
|
dcc->cps = (dcc->ack - dcc->resumable) / sec;
|
|
|
|
else
|
|
|
|
dcc->cps = (dcc->pos - dcc->resumable) / sec;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dcc_send_ack (struct DCC *dcc)
|
|
|
|
{
|
|
|
|
/* send in 32-bit big endian */
|
|
|
|
guint32 pos = htonl (dcc->pos & 0xffffffff);
|
|
|
|
send (dcc->sok, (char *) &pos, 4, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
dcc_read (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
|
|
|
|
{
|
|
|
|
char *old;
|
|
|
|
char buf[4096];
|
|
|
|
int n;
|
|
|
|
gboolean need_ack = FALSE;
|
|
|
|
|
|
|
|
if (dcc->fp == -1)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* try to create the download dir (even if it exists, no harm) */
|
2012-11-03 13:24:25 -04:00
|
|
|
g_mkdir (prefs.hex_dcc_dir, 0700);
|
2011-02-23 22:14:30 -05:00
|
|
|
|
|
|
|
if (dcc->resumable)
|
|
|
|
{
|
2014-12-06 17:02:45 -05:00
|
|
|
gchar *filename_fs = g_filename_from_utf8(dcc->destfile, -1, NULL, NULL, NULL);
|
|
|
|
dcc->fp = g_open(dcc->destfile, O_WRONLY | O_APPEND | OFLAGS, 0);
|
|
|
|
g_free (filename_fs);
|
|
|
|
|
2011-02-23 22:14:30 -05:00
|
|
|
dcc->pos = dcc->resumable;
|
|
|
|
dcc->ack = dcc->resumable;
|
2014-12-06 17:02:45 -05:00
|
|
|
}
|
|
|
|
else
|
2011-02-23 22:14:30 -05:00
|
|
|
{
|
2014-12-06 17:02:45 -05:00
|
|
|
gchar *filename_fs;
|
|
|
|
|
2012-10-22 05:30:38 -04:00
|
|
|
if (g_access (dcc->destfile, F_OK) == 0)
|
2011-02-23 22:14:30 -05:00
|
|
|
{
|
|
|
|
n = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
n++;
|
2014-12-17 18:49:59 -05:00
|
|
|
g_snprintf (buf, sizeof (buf), "%s.%d", dcc->destfile, n);
|
2011-02-23 22:14:30 -05:00
|
|
|
}
|
2014-12-06 17:02:45 -05:00
|
|
|
while (g_access (buf, F_OK) == 0);
|
2011-02-23 22:14:30 -05:00
|
|
|
|
|
|
|
old = dcc->destfile;
|
2012-10-22 05:30:38 -04:00
|
|
|
dcc->destfile = g_strdup (buf);
|
2011-02-23 22:14:30 -05:00
|
|
|
|
|
|
|
EMIT_SIGNAL (XP_TE_DCCRENAME, dcc->serv->front_session,
|
|
|
|
old, dcc->destfile, NULL, NULL, 0);
|
|
|
|
g_free (old);
|
|
|
|
}
|
2014-12-06 17:02:45 -05:00
|
|
|
|
|
|
|
filename_fs = g_filename_from_utf8 (dcc->destfile, -1, NULL, NULL, NULL);
|
|
|
|
dcc->fp = g_open (filename_fs, OFLAGS | O_TRUNC | O_WRONLY | O_CREAT, prefs.hex_dcc_permissions);
|
|
|
|
g_free (filename_fs);
|
2011-02-23 22:14:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (dcc->fp == -1)
|
|
|
|
{
|
|
|
|
/* the last executed function is open(), errno should be valid */
|
|
|
|
EMIT_SIGNAL (XP_TE_DCCFILEERR, dcc->serv->front_session, dcc->destfile,
|
|
|
|
errorstring (errno), NULL, NULL, 0);
|
|
|
|
dcc_close (dcc, STAT_FAILED, FALSE);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
if (dcc->throttled)
|
|
|
|
{
|
|
|
|
if (need_ack)
|
|
|
|
dcc_send_ack (dcc);
|
|
|
|
|
|
|
|
fe_input_remove (dcc->iotag);
|
|
|
|
dcc->iotag = 0;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!dcc->iotag)
|
|
|
|
dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX, dcc_read, dcc);
|
|
|
|
|
|
|
|
n = recv (dcc->sok, buf, sizeof (buf), 0);
|
|
|
|
if (n < 1)
|
|
|
|
{
|
|
|
|
if (n < 0)
|
|
|
|
{
|
|
|
|
if (would_block ())
|
|
|
|
{
|
|
|
|
if (need_ack)
|
|
|
|
dcc_send_ack (dcc);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EMIT_SIGNAL (XP_TE_DCCRECVERR, dcc->serv->front_session, dcc->file,
|
|
|
|
dcc->destfile, dcc->nick,
|
|
|
|
errorstring ((n < 0) ? sock_error () : 0), 0);
|
|
|
|
/* send ack here? but the socket is dead */
|
|
|
|
/*if (need_ack)
|
|
|
|
dcc_send_ack (dcc);*/
|
|
|
|
dcc_close (dcc, STAT_FAILED, FALSE);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (write (dcc->fp, buf, n) == -1) /* could be out of hdd space */
|
|
|
|
{
|
|
|
|
EMIT_SIGNAL (XP_TE_DCCRECVERR, dcc->serv->front_session, dcc->file,
|
|
|
|
dcc->destfile, dcc->nick, errorstring (errno), 0);
|
|
|
|
if (need_ack)
|
|
|
|
dcc_send_ack (dcc);
|
|
|
|
dcc_close (dcc, STAT_FAILED, FALSE);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
dcc->lasttime = time (0);
|
|
|
|
dcc->pos += n;
|
|
|
|
need_ack = TRUE; /* send ack when we're done recv()ing */
|
|
|
|
|
|
|
|
if (dcc->pos >= dcc->size)
|
|
|
|
{
|
|
|
|
dcc_send_ack (dcc);
|
|
|
|
dcc_close (dcc, STAT_DONE, FALSE);
|
|
|
|
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 */
|
2013-01-09 17:37:57 -05:00
|
|
|
/* cppcheck-suppress deallocuse */
|
2014-12-06 17:02:45 -05:00
|
|
|
sprintf (buf, "%" G_GINT64_FORMAT, dcc->cps);
|
2011-02-23 22:14:30 -05:00
|
|
|
EMIT_SIGNAL (XP_TE_DCCRECVCOMP, dcc->serv->front_session,
|
|
|
|
dcc->file, dcc->destfile, dcc->nick, buf, 0);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dcc_open_query (server *serv, char *nick)
|
|
|
|
{
|
2012-10-22 07:49:28 -04:00
|
|
|
if (prefs.hex_gui_autoopen_dialog)
|
2011-02-23 22:14:30 -05:00
|
|
|
open_query (serv, nick, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
dcc_did_connect (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
|
|
|
|
{
|
|
|
|
int er;
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
if (condition & G_IO_ERR)
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
|
|
|
|
/* find the last errno for this socket */
|
|
|
|
len = sizeof (er);
|
|
|
|
getsockopt (dcc->sok, SOL_SOCKET, SO_ERROR, (char *)&er, &len);
|
|
|
|
EMIT_SIGNAL (XP_TE_DCCCONFAIL, dcc->serv->front_session,
|
|
|
|
dcctypes[dcc->type], dcc->nick, errorstring (er),
|
|
|
|
NULL, 0);
|
|
|
|
dcc->dccstat = STAT_FAILED;
|
|
|
|
fe_dcc_update (dcc);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
2012-07-21 08:26:19 -04:00
|
|
|
struct sockaddr_in addr;
|
|
|
|
|
2011-02-23 22:14:30 -05:00
|
|
|
memset (&addr, 0, sizeof (addr));
|
|
|
|
addr.sin_port = htons (dcc->port);
|
|
|
|
addr.sin_family = AF_INET;
|
|
|
|
addr.sin_addr.s_addr = htonl (dcc->addr);
|
|
|
|
|
|
|
|
/* check if it's already connected; This always fails on winXP */
|
|
|
|
if (connect (dcc->sok, (struct sockaddr *) &addr, sizeof (addr)) != 0)
|
|
|
|
{
|
|
|
|
er = sock_error ();
|
|
|
|
if (er != EISCONN)
|
|
|
|
{
|
|
|
|
EMIT_SIGNAL (XP_TE_DCCCONFAIL, dcc->serv->front_session,
|
|
|
|
dcctypes[dcc->type], dcc->nick, errorstring (er),
|
|
|
|
NULL, 0);
|
|
|
|
dcc->dccstat = STAT_FAILED;
|
|
|
|
fe_dcc_update (dcc);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
dcc_connect_finished (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
|
|
|
|
{
|
|
|
|
char host[128];
|
|
|
|
|
|
|
|
if (dcc->iotag)
|
|
|
|
{
|
|
|
|
fe_input_remove (dcc->iotag);
|
|
|
|
dcc->iotag = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!dcc_did_connect (source, condition, dcc))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
dcc->dccstat = STAT_ACTIVE;
|
2014-12-17 18:49:59 -05:00
|
|
|
g_snprintf (host, sizeof host, "%s:%d", net_ip (dcc->addr), dcc->port);
|
2011-02-23 22:14:30 -05:00
|
|
|
|
|
|
|
switch (dcc->type)
|
|
|
|
{
|
|
|
|
case TYPE_RECV:
|
|
|
|
dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX, dcc_read, dcc);
|
|
|
|
EMIT_SIGNAL (XP_TE_DCCCONRECV, dcc->serv->front_session,
|
|
|
|
dcc->nick, host, dcc->file, NULL, 0);
|
|
|
|
break;
|
|
|
|
case TYPE_SEND:
|
|
|
|
/* passive send */
|
2012-10-22 06:10:55 -04:00
|
|
|
dcc->fastsend = prefs.hex_dcc_fast_send;
|
2011-02-23 22:14:30 -05:00
|
|
|
if (dcc->fastsend)
|
|
|
|
dcc->wiotag = fe_input_add (dcc->sok, FIA_WRITE, dcc_send_data, dcc);
|
|
|
|
dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX, dcc_read_ack, dcc);
|
|
|
|
dcc_send_data (NULL, 0, (gpointer)dcc);
|
|
|
|
EMIT_SIGNAL (XP_TE_DCCCONSEND, dcc->serv->front_session,
|
|
|
|
dcc->nick, host, dcc->file, NULL, 0);
|
|
|
|
break;
|
|
|
|
case TYPE_CHATSEND: /* pchat */
|
|
|
|
dcc_open_query (dcc->serv, dcc->nick);
|
|
|
|
case TYPE_CHATRECV: /* normal chat */
|
|
|
|
dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX, dcc_read_chat, dcc);
|
2014-12-28 06:37:25 -05:00
|
|
|
dcc->dccchat = g_new0 (struct dcc_chat, 1);
|
2011-02-23 22:14:30 -05:00
|
|
|
EMIT_SIGNAL (XP_TE_DCCCONCHAT, dcc->serv->front_session,
|
|
|
|
dcc->nick, host, NULL, NULL, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
dcc->starttime = time (0);
|
|
|
|
dcc->lasttime = dcc->starttime;
|
|
|
|
fe_dcc_update (dcc);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
read_proxy (struct DCC *dcc)
|
|
|
|
{
|
|
|
|
struct proxy_state *proxy = dcc->proxy;
|
|
|
|
while (proxy->bufferused < proxy->buffersize)
|
|
|
|
{
|
|
|
|
int ret = recv (dcc->sok, &proxy->buffer[proxy->bufferused],
|
|
|
|
proxy->buffersize - proxy->bufferused, 0);
|
|
|
|
if (ret > 0)
|
|
|
|
proxy->bufferused += ret;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (would_block ())
|
|
|
|
return FALSE;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dcc->dccstat = STAT_FAILED;
|
|
|
|
fe_dcc_update (dcc);
|
|
|
|
if (dcc->iotag)
|
|
|
|
{
|
|
|
|
fe_input_remove (dcc->iotag);
|
|
|
|
dcc->iotag = 0;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
write_proxy (struct DCC *dcc)
|
|
|
|
{
|
|
|
|
struct proxy_state *proxy = dcc->proxy;
|
|
|
|
while (proxy->bufferused < proxy->buffersize)
|
|
|
|
{
|
|
|
|
int ret = send (dcc->sok, &proxy->buffer[proxy->bufferused],
|
|
|
|
proxy->buffersize - proxy->bufferused, 0);
|
|
|
|
if (ret >= 0)
|
|
|
|
proxy->bufferused += ret;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (would_block ())
|
|
|
|
return FALSE;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dcc->dccstat = STAT_FAILED;
|
|
|
|
fe_dcc_update (dcc);
|
|
|
|
if (dcc->wiotag)
|
|
|
|
{
|
|
|
|
fe_input_remove (dcc->wiotag);
|
|
|
|
dcc->wiotag = 0;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
proxy_read_line (struct DCC *dcc)
|
|
|
|
{
|
|
|
|
struct proxy_state *proxy = dcc->proxy;
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
proxy->buffersize = proxy->bufferused + 1;
|
|
|
|
if (!read_proxy (dcc))
|
|
|
|
return FALSE;
|
|
|
|
if (proxy->buffer[proxy->bufferused - 1] == '\n'
|
|
|
|
|| proxy->bufferused == MAX_PROXY_BUFFER)
|
|
|
|
{
|
|
|
|
proxy->buffer[proxy->bufferused - 1] = 0;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
dcc_wingate_proxy_traverse (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
|
|
|
|
{
|
|
|
|
struct proxy_state *proxy = dcc->proxy;
|
|
|
|
if (proxy->phase == 0)
|
|
|
|
{
|
2014-12-17 18:49:59 -05:00
|
|
|
proxy->buffersize = g_snprintf ((char*) proxy->buffer, MAX_PROXY_BUFFER,
|
2011-02-23 22:14:30 -05:00
|
|
|
"%s %d\r\n", net_ip(dcc->addr),
|
|
|
|
dcc->port);
|
|
|
|
proxy->bufferused = 0;
|
|
|
|
dcc->wiotag = fe_input_add (dcc->sok, FIA_WRITE|FIA_EX,
|
|
|
|
dcc_wingate_proxy_traverse, dcc);
|
|
|
|
++proxy->phase;
|
|
|
|
}
|
|
|
|
if (proxy->phase == 1)
|
|
|
|
{
|
|
|
|
if (!read_proxy (dcc))
|
|
|
|
return TRUE;
|
|
|
|
fe_input_remove (dcc->wiotag);
|
|
|
|
dcc->wiotag = 0;
|
|
|
|
dcc_connect_finished (source, 0, dcc);
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct sock_connect
|
|
|
|
{
|
|
|
|
char version;
|
|
|
|
char type;
|
|
|
|
guint16 port;
|
|
|
|
guint32 address;
|
|
|
|
char username[10];
|
|
|
|
};
|
|
|
|
static gboolean
|
|
|
|
dcc_socks_proxy_traverse (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
|
|
|
|
{
|
|
|
|
struct proxy_state *proxy = dcc->proxy;
|
|
|
|
|
|
|
|
if (proxy->phase == 0)
|
|
|
|
{
|
|
|
|
struct sock_connect sc;
|
|
|
|
sc.version = 4;
|
|
|
|
sc.type = 1;
|
|
|
|
sc.port = htons (dcc->port);
|
|
|
|
sc.address = htonl (dcc->addr);
|
2012-10-22 08:50:36 -04:00
|
|
|
strncpy (sc.username, prefs.hex_irc_user_name, 9);
|
2011-02-23 22:14:30 -05:00
|
|
|
memcpy (proxy->buffer, &sc, sizeof (sc));
|
|
|
|
proxy->buffersize = 8 + strlen (sc.username) + 1;
|
|
|
|
proxy->bufferused = 0;
|
|
|
|
dcc->wiotag = fe_input_add (dcc->sok, FIA_WRITE|FIA_EX,
|
|
|
|
dcc_socks_proxy_traverse, dcc);
|
|
|
|
++proxy->phase;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (proxy->phase == 1)
|
|
|
|
{
|
|
|
|
if (!write_proxy (dcc))
|
|
|
|
return TRUE;
|
|
|
|
fe_input_remove (dcc->wiotag);
|
|
|
|
dcc->wiotag = 0;
|
|
|
|
proxy->bufferused = 0;
|
|
|
|
proxy->buffersize = 8;
|
|
|
|
dcc->iotag = fe_input_add (dcc->sok, FIA_READ|FIA_EX,
|
|
|
|
dcc_socks_proxy_traverse, dcc);
|
|
|
|
++proxy->phase;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (proxy->phase == 2)
|
|
|
|
{
|
|
|
|
if (!read_proxy (dcc))
|
|
|
|
return TRUE;
|
|
|
|
fe_input_remove (dcc->iotag);
|
|
|
|
dcc->iotag = 0;
|
|
|
|
if (proxy->buffer[1] == 90)
|
|
|
|
dcc_connect_finished (source, 0, dcc);
|
|
|
|
else
|
|