⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dcc.c

📁 The major functionality added in this release includes: - Rootless mode in X11 - Widget Templt
💻 C
📖 第 1 页 / 共 2 页
字号:
/* X-Chat * Copyright (C) 1998 Peter Zelezny. * * 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 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * 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) */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <errno.h>#include <sys/stat.h>#include <unistd.h>#include <fcntl.h>#define WANTSOCKET#define WANTARPA#include "inet.h"#include "xchat.h"#include "perlc.h"#include "util.h"#include "plugin.h"#include "fe.h"#include "outbound.h"#include "inbound.h"#include "network.h"#include "text.h"#include "xchatc.h"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 struct DCC *new_dcc (void);static voiddcc_calc_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;}/* this is called from xchat.c:xchat_misc_checks() every 2 seconds. */voiddcc_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;		if (dcc->dccstat == STAT_ACTIVE)		{			dcc_calc_cps (dcc);			switch (dcc->type)			{			case TYPE_SEND:				fe_dcc_update_send (dcc);				break;			case TYPE_RECV:				fe_dcc_update_recv (dcc);				break;			}		}		switch (dcc->dccstat)		{		case STAT_ACTIVE:			if (dcc->type == TYPE_SEND || dcc->type == TYPE_RECV)			{				if (prefs.dccstalltimeout > 0)				{					if (tim - dcc->lasttime > prefs.dccstalltimeout)					{						EMIT_SIGNAL (XP_TE_DCCSTALL, dcc->serv->front_session,										 dcctypes[(int) dcc->type],										 file_part (dcc->file), dcc->nick, NULL, 0);						dcc_close (dcc, 0, TRUE);					}				}			}			break;		case STAT_QUEUED:			if (dcc->type == TYPE_SEND || dcc->type == TYPE_CHATSEND)			{				if (tim - dcc->offertime > prefs.dcctimeout)				{					if (prefs.dcctimeout > 0)					{						EMIT_SIGNAL (XP_TE_DCCTOUT, dcc->serv->front_session,										 dcctypes[(int) dcc->type],										 file_part (dcc->file), dcc->nick, NULL, 0);						dcc_close (dcc, 0, TRUE);					}				}			}			break;		}		list = next;	}}static intdcc_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_port = htons (dcc->port);	addr.sin_family = AF_INET;	addr.sin_addr.s_addr = htonl (dcc->addr);	set_nonblocking (sok);	connect (sok, (struct sockaddr *) &addr, sizeof (addr));	return sok;}static voidupdate_dcc_window (int type){	switch (type)	{	case TYPE_SEND:		fe_dcc_update_send_win ();		break;	case TYPE_RECV:		fe_dcc_update_recv_win ();		break;	case TYPE_CHATRECV:	case TYPE_CHATSEND:		fe_dcc_update_chat_win ();		break;	}}voiddcc_close (struct DCC *dcc, int dccstat, int destroy){	char type = dcc->type;	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;	}	if (dcc->fp != -1)	{		close (dcc->fp);		dcc->fp = -1;	}	dcc->dccstat = dccstat;	if (dcc->dccchat)	{		free (dcc->dccchat);		dcc->dccchat = NULL;	}	if (destroy)	{		dcc_list = g_slist_remove (dcc_list, dcc);		if (dcc->file)			free (dcc->file);		if (dcc->destfile)			free (dcc->destfile);		free (dcc->nick);		free (dcc);		update_dcc_window (type);		return;	}	switch (type)	{	case TYPE_SEND:		fe_dcc_update_send (dcc);		break;	case TYPE_RECV:		fe_dcc_update_recv (dcc);		break;	default:		update_dcc_window (type);	}}voiddcc_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){#ifdef USE_TRANS	unsigned char *tbuf;#define TRANS_STAT_BUF_LEN 1024	static unsigned char sbuf[TRANS_STAT_BUF_LEN];#endif	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);		dcc->size += len;#ifdef USE_TRANS		if (prefs.use_trans)		{			if (len >= TRANS_STAT_BUF_LEN)				tbuf = malloc (len + 1);			else				tbuf = sbuf;			if (!tbuf)			{				return 0;			}			strcpy (tbuf, text);			user2serv (tbuf);			send (dcc->sok, tbuf, len, 0);			if (tbuf != sbuf)			{				free (tbuf);			}		} else		{#endif			send (dcc->sok, text, len, 0);#ifdef USE_TRANS		}#endif		send (dcc->sok, "\n", 1, 0);		fe_dcc_update_chat_win ();		return dcc;	}	return 0;}/* returns: 0 - ok				1 - the dcc is closed! */static intdcc_chat_line (struct DCC *dcc, char *line, char *tbuf){#ifdef USE_PERL	int skip;	char *host_n_nick_n_message;	GSList *list = dcc_list;	host_n_nick_n_message = malloc (strlen (dcc->nick) + strlen (line) + 26);	sprintf (host_n_nick_n_message, "%s %d %s: %s",				net_ip (dcc->addr), dcc->port, dcc->nick, line);	skip = perl_dcc_chat (find_session_from_channel (dcc->nick, dcc->serv),								 dcc->serv, host_n_nick_n_message);	free (host_n_nick_n_message);	/* Perl code may have closed the chat. */	while (list) 	{		if (((struct DCC *)list->data) == dcc) break;		list = list->next;	}	if (list == 0)		return 1;	if (skip)		return 0;#endif	fe_checkurl (line);	if (line[0] == 1 && !strncasecmp (line + 1, "ACTION", 6))	{		session *sess;		char *po = strchr (line + 8, '\001');		if (po)			po[0] = 0;		sess = find_session_from_channel (dcc->nick, dcc->serv);		if (!sess)			sess = dcc->serv->front_session;		channel_action (sess, tbuf, dcc->serv->nick, dcc->nick,							 line + 8, FALSE);	} else	{#ifdef USE_TRANS		if (prefs.use_trans)			serv2user (line);#endif		private_msg (dcc->serv, tbuf, dcc->nick, "", line);	}	return 0;}static gbooleandcc_read_chat (GIOChannel *source, GIOCondition condition, struct DCC *dcc){	int i, len, dead;	char tbuf[1226];	char lbuf[1026];	unsigned char *temp;	while (1)	{		len = recv (dcc->sok, lbuf, sizeof (lbuf) - 2, 0);		if (len < 1)		{			if (len < 0)			{				if (would_block_again ())					return TRUE;			}			sprintf (tbuf, "%d", dcc->port);			EMIT_SIGNAL (XP_TE_DCCCHATF, dcc->serv->front_session, dcc->nick,							 net_ip (dcc->addr), tbuf, NULL, 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;				if (prefs.stripcolor)				{					temp = strip_color (dcc->dccchat->linebuf);					dead = dcc_chat_line (dcc, temp, tbuf);					free (temp);				} else				{					dead = dcc_chat_line (dcc, dcc->dccchat->linebuf, tbuf);				}				if (dead) /* the dcc has been closed, don't use (DCC *)! */					return TRUE;				dcc->pos += dcc->dccchat->pos;				dcc->dccchat->pos = 0;				fe_dcc_update_chat_win ();				break;			default:				dcc->dccchat->linebuf[dcc->dccchat->pos] = lbuf[i];				if (dcc->dccchat->pos < 1022)					dcc->dccchat->pos++;			}			i++;		}	}}static gbooleandcc_read (GIOChannel *source, GIOCondition condition, struct DCC *dcc){	char buf[4096];	guint32 pos;	int n;	if (dcc->fp == -1)	{		if (dcc->resumable)		{			dcc->fp = open (dcc->destfile, O_WRONLY | O_APPEND | OFLAGS);			dcc->pos = dcc->resumable;			dcc->ack = dcc->resumable;		} else		{			if (access (dcc->destfile, F_OK) == 0)			{				n = 0;				do				{					n++;					sprintf (buf, "%s.%d", dcc->destfile, n);				}				while (access (buf, F_OK) == 0);				EMIT_SIGNAL (XP_TE_DCCRENAME, dcc->serv->front_session,								 dcc->destfile, buf, NULL, NULL, 0);				free (dcc->destfile);				dcc->destfile = strdup (buf);			}			dcc->fp =				open (dcc->destfile, OFLAGS | O_TRUNC | O_WRONLY | O_CREAT,						prefs.dccpermissions);		}	}	if (dcc->fp == -1)	{		EMIT_SIGNAL (XP_TE_DCCFILEERR, dcc->serv->front_session, dcc->destfile,						 NULL, NULL, NULL, 0);		dcc_close (dcc, STAT_FAILED, FALSE);		return TRUE;	}	while (1)	{		n = recv (dcc->sok, buf, sizeof (buf), 0);		if (n < 1)		{			if (n < 0)			{				if (would_block_again ())					return TRUE;			}			EMIT_SIGNAL (XP_TE_DCCRECVERR, dcc->serv->front_session, dcc->file,							 dcc->destfile, dcc->nick, NULL, 0);			dcc_close (dcc, STAT_FAILED, FALSE);			return TRUE;		}		write (dcc->fp, buf, n);		dcc->pos += n;		pos = htonl (dcc->pos);		send (dcc->sok, (char *) &pos, 4, 0);		dcc->lasttime = time (0);		dcc_calc_cps (dcc);		if (dcc->pos >= dcc->size)		{			sprintf (buf, "%d", dcc->cps);			dcc_close (dcc, STAT_DONE, FALSE);			EMIT_SIGNAL (XP_TE_DCCRECVCOMP, dcc->serv->front_session,							 dcc->file, dcc->destfile, dcc->nick, buf, 0);			return TRUE;		}	}}static gbooleandcc_connect_finished (GIOChannel *source, GIOCondition condition, struct DCC *dcc){	int er, sok = dcc->sok;	char host[128];	struct sockaddr_in addr;	fe_input_remove (dcc->iotag);	dcc->iotag = 0;	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 */	if (connect (sok, (struct sockaddr *) &addr, sizeof (addr)) != 0)	{		er = sock_error ();#ifndef WIN32		if (er != EISCONN)#else		if (er != WSAEISCONN)#endif		{			EMIT_SIGNAL (XP_TE_DCCCONFAIL, dcc->serv->front_session,							 dcctypes[(int) dcc->type], dcc->nick, errorstring (er),							 NULL, 0);			dcc->dccstat = STAT_FAILED;			update_dcc_window (dcc->type);			return TRUE;		}	}	dcc->dccstat = STAT_ACTIVE;	switch (dcc->type)	{	case TYPE_RECV:		dcc->iotag = fe_input_add (dcc->sok, 1, 0, 1, dcc_read, dcc);		break;	case TYPE_CHATRECV:		dcc->iotag = fe_input_add (dcc->sok, 1, 0, 1, dcc_read_chat, dcc);		dcc->dccchat = malloc (sizeof (struct dcc_chat));		dcc->dccchat->pos = 0;		break;	}	update_dcc_window (dcc->type);	dcc->starttime = time (0);	dcc->lasttime = dcc->starttime;	snprintf (host, sizeof host, "%s:%d", net_ip (dcc->addr), dcc->port);	EMIT_SIGNAL (XP_TE_DCCCON, dcc->serv->front_session,					 dcctypes[(int) dcc->type], dcc->nick, host, "to", 0);	return TRUE;}static voiddcc_connect (struct DCC *dcc){	if (dcc->dccstat == STAT_CONNECTING)		return;	dcc->dccstat = STAT_CONNECTING;	dcc->sok = dcc_connect_sok (dcc);	if (dcc->sok == -1)	{		dcc->dccstat = STAT_FAILED;		update_dcc_window (dcc->type);		return;	}	dcc->iotag = fe_input_add (dcc->sok, 0, 1, 1, dcc_connect_finished, dcc);	if (dcc->type == TYPE_RECV)		fe_dcc_update_recv (dcc);	else		fe_dcc_update_chat_win ();}static gbooleandcc_send_data (GIOChannel *source, GIOCondition condition, struct DCC *dcc){	char *buf;	int len, sent, sok = dcc->sok;	if (prefs.dcc_blocksize < 1) /* this is too little! */		prefs.dcc_blocksize = 1024;	if (prefs.dcc_blocksize > 102400)	/* this is too much! */		prefs.dcc_blocksize = 102400;	buf = malloc (prefs.dcc_blocksize);	if (!buf)		return TRUE;	lseek (dcc->fp, dcc->pos, SEEK_SET);	len = read (dcc->fp, buf, prefs.dcc_blocksize);	if (len < 1)		goto abortit;	sent = send (sok, buf, len, 0);	if (send < 0 && !(would_block ()))	{abortit:		EMIT_SIGNAL (XP_TE_DCCSENDFAIL, dcc->serv->front_session,						 file_part (dcc->file), dcc->nick, NULL, NULL, 0);		dcc_close (dcc, STAT_FAILED, FALSE);		free (buf);		return TRUE;	}	if (sent > 0)	{		dcc->pos += sent;		dcc->lasttime = time (0);		dcc_calc_cps (dcc);	}	/* have we sent it all yet? */	if (dcc->pos >= dcc->size)	{		/* it's all sent now, so remove the WRITE/SEND handler */		if (dcc->wiotag)		{			fe_input_remove (dcc->wiotag);			dcc->wiotag = 0;		}	}	free (buf);	return TRUE;}static gbooleandcc_read_ack (GIOChannel *source, GIOCondition condition, struct DCC *dcc){	int len;	guint32 ack;	char buf[16];	int sok = dcc->sok;	len = recv (sok, (char *) &ack, 4, MSG_PEEK);	if (len < 1)	{		if (len < 0)		{			if (would_block_again ())				return TRUE;		}		EMIT_SIGNAL (XP_TE_DCCSENDFAIL, dcc->serv->front_session,						 file_part (dcc->file), dcc->nick, NULL, NULL, 0);		dcc_close (dcc, STAT_FAILED, FALSE);		return TRUE;	}	if (len < 4)		return TRUE;	recv (sok, (char *) &ack, 4, 0);	dcc->ack = ntohl (ack);	/* fix for BitchX */	if (dcc->ack < dcc->resumable)		dcc->ackoffset = TRUE;	if (dcc->ackoffset)		dcc->ack += dcc->resumable;	if (!dcc->fastsend)	{		if (dcc->ack < dcc->pos)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -