📄 send_file.c
字号:
/** * @file send_file.c * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 */#include "send_file.h"#include "debug.h"#include "network.h"#include "notify.h"#include "buddy_status.h"#include "crypt.h"#include "file_trans.h"#include "header_info.h"#include "im.h"#include "keep_alive.h"#include "packet_parse.h"#include "qq.h"#include "send_core.h"#include "utils.h"enum{ QQ_FILE_TRANS_REQ = 0x0035, QQ_FILE_TRANS_ACC_UDP = 0x0037, QQ_FILE_TRANS_ACC_TCP = 0x0003, QQ_FILE_TRANS_DENY_UDP = 0x0039, QQ_FILE_TRANS_DENY_TCP = 0x0005, QQ_FILE_TRANS_NOTIFY = 0x003b, QQ_FILE_TRANS_NOTIFY_ACK = 0x003c, QQ_FILE_TRANS_CANCEL = 0x0049, QQ_FILE_TRANS_PASV = 0x003f};static int _qq_in_same_lan(ft_info *info){ if (info->remote_internet_ip == info->local_internet_ip) return 1; purple_debug(PURPLE_DEBUG_INFO, "QQ", "Not in the same LAN, remote internet ip[%x], local internet ip[%x]\n", info->remote_internet_ip , info->local_internet_ip); return 0;}static int _qq_xfer_init_udp_channel(ft_info *info){ struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; if (!_qq_in_same_lan(info)) { sin.sin_port = g_htons(info->remote_major_port); sin.sin_addr.s_addr = g_htonl(info->remote_internet_ip); } else { sin.sin_port = g_htons(info->remote_minor_port); sin.sin_addr.s_addr = g_htonl(info->remote_real_ip); } return 0;}/* these 2 functions send and recv buffer from/to UDP channel */static ssize_t _qq_xfer_udp_recv(guint8 *buf, size_t len, PurpleXfer *xfer){ struct sockaddr_in sin; socklen_t sinlen; ft_info *info; gint r; info = (ft_info *) xfer->data; sinlen = sizeof(sin); r = recvfrom(info->recv_fd, buf, len, 0, (struct sockaddr *) &sin, &sinlen); purple_debug(PURPLE_DEBUG_INFO, "QQ", "==> recv %d bytes from File UDP Channel, remote ip[%s], remote port[%d]\n", r, inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port)); return r;}/*static ssize_t _qq_xfer_udp_send(const char *buf, size_t len, PurpleXfer *xfer){ ft_info *info; info = (ft_info *) xfer->data; return send(info->sender_fd, buf, len, 0);}*/static ssize_t _qq_xfer_udp_send(const guint8 *buf, size_t len, PurpleXfer *xfer){ struct sockaddr_in sin; ft_info *info; info = (ft_info *) xfer->data; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; if (!_qq_in_same_lan(info)) { sin.sin_port = g_htons(info->remote_major_port); sin.sin_addr.s_addr = g_htonl(info->remote_internet_ip); } else if (info->use_major) { sin.sin_port = g_htons(info->remote_major_port); sin.sin_addr.s_addr = g_htonl(info->remote_real_ip); } else { sin.sin_port = g_htons(info->remote_minor_port); sin.sin_addr.s_addr = g_htonl(info->remote_real_ip); } purple_debug(PURPLE_DEBUG_INFO, "QQ", "sending to channel: %d.%d.%d.%d:%d\n", sin.sin_addr.s_addr & 0xff, (sin.sin_addr.s_addr >> 8) & 0xff, (sin.sin_addr.s_addr >> 16) & 0xff, sin.sin_addr.s_addr >> 24, g_ntohs(sin.sin_port) ); return sendto(info->sender_fd, buf, len, 0, (struct sockaddr *) &sin, sizeof(sin));}/* user-defined functions for purple_xfer_read and purple_xfer_write *//*static ssize_t _qq_xfer_read(char **buf, PurpleXfer *xfer){ *buf = g_newa(char, QQ_FILE_FRAGMENT_MAXLEN + 100); return _qq_xfer_udp_recv(*buf, QQ_FILE_FRAGMENT_MAXLEN + 100, xfer);}*/gssize _qq_xfer_write(const guint8 *buf, size_t len, PurpleXfer *xfer){ return _qq_xfer_udp_send(buf, len, xfer);}static void _qq_xfer_recv_packet(gpointer data, gint source, PurpleInputCondition condition){ PurpleXfer *xfer = (PurpleXfer *) data; PurpleAccount *account = purple_xfer_get_account(xfer); PurpleConnection *gc = purple_account_get_connection(account); guint8 *buf; gint size; /* FIXME: It seems that the transfer never use a packet * larger than 1500 bytes, so if it happened to be a * larger packet, either error occured or protocol should * be modified */ ft_info *info; info = xfer->data; g_return_if_fail (source == info->recv_fd); buf = g_newa(guint8, 1500); size = _qq_xfer_udp_recv(buf, 1500, xfer); qq_process_recv_file(gc, buf, size);}/* start file transfer process *//*static void _qq_xfer_send_start (PurpleXfer *xfer){ PurpleAccount *account; PurpleConnection *gc; ft_info *info; account = purple_xfer_get_account(xfer); gc = purple_account_get_connection(account); info = (ft_info *) xfer->data;}*//*static void _qq_xfer_send_ack (PurpleXfer *xfer, const char *buffer, size_t len){ PurpleAccount *account; PurpleConnection *gc; account = purple_xfer_get_account(xfer); gc = purple_account_get_connection(account); qq_process_recv_file(gc, (guint8 *) buffer, len);}*//*static void _qq_xfer_recv_start(PurpleXfer *xfer){}*/static void _qq_xfer_end(PurpleXfer *xfer){ ft_info *info; g_return_if_fail(xfer != NULL && xfer->data != NULL); info = (ft_info *) xfer->data; qq_xfer_close_file(xfer); if (info->dest_fp != NULL) { fclose(info->dest_fp); purple_debug(PURPLE_DEBUG_INFO, "QQ", "file closed\n"); } if (info->major_fd != 0) { close(info->major_fd); purple_debug(PURPLE_DEBUG_INFO, "QQ", "major port closed\n"); } if (info->minor_fd != 0) { close(info->minor_fd); purple_debug(PURPLE_DEBUG_INFO, "QQ", "minor port closed\n"); } /* if (info->buffer != NULL) { munmap(info->buffer, purple_xfer_get_size(xfer)); purple_debug(PURPLE_DEBUG_INFO, "QQ", "file mapping buffer is freed.\n"); } */ g_free(info);}static void qq_show_conn_info(ft_info *info){ gchar *internet_ip_str, *real_ip_str; guint32 ip; ip = g_htonl(info->remote_real_ip); real_ip_str = gen_ip_str((guint8 *) &ip); ip = g_htonl(info->remote_internet_ip); internet_ip_str = gen_ip_str((guint8 *) &ip); purple_debug(PURPLE_DEBUG_INFO, "QQ", "remote internet ip[%s:%d], major port[%d], real ip[%s], minor port[%d]\n", internet_ip_str, info->remote_internet_port, info->remote_major_port, real_ip_str, info->remote_minor_port ); g_free(real_ip_str); g_free(internet_ip_str);}void qq_get_conn_info(guint8 *data, guint8 **cursor, gint data_len, ft_info *info){ read_packet_data(data, cursor, data_len, info->file_session_key, 16); *cursor += 30; read_packet_b(data, cursor, data_len, &info->conn_method); read_packet_dw(data, cursor, data_len, &info->remote_internet_ip); read_packet_w(data, cursor, data_len, &info->remote_internet_port); read_packet_w(data, cursor, data_len, &info->remote_major_port); read_packet_dw(data, cursor, data_len, &info->remote_real_ip); read_packet_w(data, cursor, data_len, &info->remote_minor_port); qq_show_conn_info(info);}gint qq_fill_conn_info(guint8 *raw_data, guint8 **cursor, ft_info *info){ gint bytes; bytes = 0; /* 064: connection method, UDP 0x00, TCP 0x03 */ bytes += create_packet_b (raw_data, cursor, info->conn_method); /* 065-068: outer ip address of sender (proxy address) */ bytes += create_packet_dw (raw_data, cursor, info->local_internet_ip); /* 069-070: sender port */ bytes += create_packet_w (raw_data, cursor, info->local_internet_port); /* 071-072: the first listening port(TCP doesn't have this part) */ bytes += create_packet_w (raw_data, cursor, info->local_major_port); /* 073-076: real ip */ bytes += create_packet_dw (raw_data, cursor, info->local_real_ip); /* 077-078: the second listening port */ bytes += create_packet_w (raw_data, cursor, info->local_minor_port); return bytes;}/* fill in the common information of file transfer */static gint _qq_create_packet_file_header(guint8 *raw_data, guint8 **cursor, guint32 to_uid, guint16 message_type, qq_data *qd, gboolean seq_ack){ gint bytes; time_t now; guint16 seq; ft_info *info; bytes = 0; now = time(NULL); if (!seq_ack) seq = qd->send_seq; else { info = (ft_info *) qd->xfer->data; seq = info->send_seq; } /* 000-003: receiver uid */ bytes += create_packet_dw (raw_data, cursor, qd->uid); /* 004-007: sender uid */ bytes += create_packet_dw (raw_data, cursor, to_uid); /* 008-009: sender client version */ bytes += create_packet_w (raw_data, cursor, QQ_CLIENT); /* 010-013: receiver uid */ bytes += create_packet_dw (raw_data, cursor, qd->uid); /* 014-017: sender uid */ bytes += create_packet_dw (raw_data, cursor, to_uid); /* 018-033: md5 of (uid+session_key) */ bytes += create_packet_data (raw_data, cursor, qd->session_md5, 16); /* 034-035: message type */ bytes += create_packet_w (raw_data, cursor, message_type); /* 036-037: sequence number */ bytes += create_packet_w (raw_data, cursor, seq); /* 038-041: send time */ bytes += create_packet_dw (raw_data, cursor, (guint32) now); /* 042-042: always 0x00 */ bytes += create_packet_b (raw_data, cursor, 0x00); /* 043-043: sender icon */ bytes += create_packet_b (raw_data, cursor, qd->my_icon); /* 044-046: always 0x00 */ bytes += create_packet_w (raw_data, cursor, 0x0000); bytes += create_packet_b (raw_data, cursor, 0x00); /* 047-047: we use font attr */ bytes += create_packet_b (raw_data, cursor, 0x01); /* 048-051: always 0x00 */ bytes += create_packet_dw (raw_data, cursor, 0x00000000); /* 052-062: always 0x00 */ bytes += create_packet_dw (raw_data, cursor, 0x00000000); bytes += create_packet_dw (raw_data, cursor, 0x00000000); bytes += create_packet_w (raw_data, cursor, 0x0000); bytes += create_packet_b (raw_data, cursor, 0x00); /* 063: transfer_type, 0x65: FILE 0x6b: FACE */ bytes += create_packet_b (raw_data, cursor, QQ_FILE_TRANSFER_FILE); /* FIXME */ return bytes;}#if 0in_addr_t get_real_ip(){ char hostname[40]; struct hostent *host; gethostname(hostname, sizeof(hostname)); host = gethostbyname(hostname); return *(host->h_addr);}#include <sys/ioctl.h>#include <net/if.h>#define MAXINTERFACES 16in_addr_t get_real_ip(){ int fd, intrface, i; struct ifconf ifc; struct ifreq buf[MAXINTERFACES]; in_addr_t ret; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) return 0; ifc.ifc_len = sizeof(buf); ifc.ifc_buf = (caddr_t) buf; if (ioctl(fd, SIOCGIFCONF, (char *) &ifc) < 0) return 0; intrface = ifc.ifc_len / sizeof(struct ifreq); for (i = 0; i < intrface; i++) { /* buf[intrface].ifr_name */ if (ioctl(fd, SIOCGIFADDR, (char *) &buf[i]) >= 0) { ret = (((struct sockaddr_in *)(&buf[i].ifr_addr))->sin_addr).s_addr; if (ret == g_ntohl(0x7f000001)) continue; return ret; } } return 0;}#endifstatic void _qq_xfer_init_socket(PurpleXfer *xfer){ gint sockfd, listen_port = 0, i; socklen_t sin_len; struct sockaddr_in sin; ft_info *info; g_return_if_fail(xfer != NULL); g_return_if_fail(xfer->data != NULL); info = (ft_info *) xfer->data; /* debug info->local_real_ip = 0x7f000001; */ info->local_real_ip = g_ntohl(inet_addr(purple_network_get_my_ip(-1))); purple_debug(PURPLE_DEBUG_INFO, "QQ", "local real ip is %x", info->local_real_ip); for (i = 0; i < 2; i++) { sockfd = socket(PF_INET, SOCK_DGRAM, 0); g_return_if_fail(sockfd >= 0); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = 0; sin.sin_addr.s_addr = INADDR_ANY; sin_len = sizeof(sin); bind(sockfd, (struct sockaddr *) &sin, sin_len); getsockname(sockfd, (struct sockaddr *) &sin, &sin_len); listen_port = g_ntohs(sin.sin_port); switch (i) { case 0: info->local_major_port = listen_port; info->major_fd = sockfd; purple_debug(PURPLE_DEBUG_INFO, "QQ", "UDP Major Channel created on port[%d]\n", info->local_major_port); break; case 1: info->local_minor_port = listen_port; info->minor_fd = sockfd; purple_debug(PURPLE_DEBUG_INFO, "QQ", "UDP Minor Channel created on port[%d]\n", info->local_minor_port); break; } } if (_qq_in_same_lan(info)) { info->sender_fd = info->recv_fd = info->minor_fd; } else { info->sender_fd = info->recv_fd = info->major_fd; }/* xfer->watcher = purple_input_add(info->recv_fd, PURPLE_INPUT_READ, _qq_xfer_recv_packet, xfer); */}/* create the QQ_FILE_TRANS_REQ packet with file infomations */static void _qq_send_packet_file_request (PurpleConnection *gc, guint32 to_uid, gchar *filename, gint filesize){ qq_data *qd; guint8 *cursor, *raw_data; gchar *filelen_str; gint filename_len, filelen_strlen, packet_len, bytes; ft_info *info; qd = (qq_data *) gc->proto_data; info = g_new0(ft_info, 1); info->to_uid = to_uid; info->send_seq = qd->send_seq; info->local_internet_ip = g_ntohl(inet_addr(qd->my_ip)); info->local_internet_port = qd->my_port; info->local_real_ip = 0x00000000; info->conn_method = 0x00; qd->xfer->data = info; filename_len = strlen(filename); filelen_str = g_strdup_printf("%d ?ֽ?", filesize); filelen_strlen = strlen(filelen_str); packet_len = 82 + filename_len + filelen_strlen; raw_data = g_newa(guint8, packet_len); cursor = raw_data; bytes = _qq_create_packet_file_header(raw_data, &cursor, to_uid, QQ_FILE_TRANS_REQ, qd, FALSE); bytes += qq_fill_conn_info(raw_data, &cursor, info); /* 079: 0x20 */ bytes += create_packet_b (raw_data, &cursor, 0x20); /* 080: 0x1f */ bytes += create_packet_b (raw_data, &cursor, 0x1f); /* undetermined len: filename */ bytes += create_packet_data (raw_data, &cursor, (guint8 *) filename, filename_len); /* 0x1f */ bytes += create_packet_b (raw_data, &cursor, 0x1f); /* file length */ bytes += create_packet_data (raw_data, &cursor, (guint8 *) filelen_str, filelen_strlen);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -