6
* Purple is the legal property of its developers, whose names are too numerous
7
* to list here. Please refer to the COPYRIGHT file distributed with this
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
15
* This program is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
27
#include "send_file.h"
32
#include "buddy_list.h"
33
#include "file_trans.h"
34
#include "qq_define.h"
37
#include "packet_parse.h"
38
#include "qq_network.h"
43
QQ_FILE_TRANS_REQ = 0x0035,
44
QQ_FILE_TRANS_ACC_UDP = 0x0037,
45
QQ_FILE_TRANS_ACC_TCP = 0x0003,
46
QQ_FILE_TRANS_DENY_UDP = 0x0039,
47
QQ_FILE_TRANS_DENY_TCP = 0x0005,
48
QQ_FILE_TRANS_NOTIFY = 0x003b,
49
QQ_FILE_TRANS_NOTIFY_ACK = 0x003c,
50
QQ_FILE_TRANS_CANCEL = 0x0049,
51
QQ_FILE_TRANS_PASV = 0x003f
54
static int _qq_in_same_lan(ft_info *info)
56
if (info->remote_internet_ip == info->local_internet_ip) return 1;
57
purple_debug_info("QQ",
58
"Not in the same LAN, remote internet ip[%x], local internet ip[%x]\n",
59
info->remote_internet_ip
60
, info->local_internet_ip);
64
static int _qq_xfer_init_udp_channel(ft_info *info)
66
struct sockaddr_in sin;
67
memset(&sin, 0, sizeof(sin));
68
sin.sin_family = AF_INET;
69
if (!_qq_in_same_lan(info)) {
70
sin.sin_port = g_htons(info->remote_major_port);
71
sin.sin_addr.s_addr = g_htonl(info->remote_internet_ip);
73
sin.sin_port = g_htons(info->remote_minor_port);
74
sin.sin_addr.s_addr = g_htonl(info->remote_real_ip);
79
/* these 2 functions send and recv buffer from/to UDP channel */
80
static ssize_t _qq_xfer_udp_recv(guint8 *buf, size_t len, PurpleXfer *xfer)
82
struct sockaddr_in sin;
87
info = (ft_info *) xfer->data;
89
r = recvfrom(info->recv_fd, buf, len, 0, (struct sockaddr *) &sin, &sinlen);
90
purple_debug_info("QQ",
91
"==> recv %d bytes from File UDP Channel, remote ip[%s], remote port[%d]\n",
92
r, inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port));
97
static ssize_t _qq_xfer_udp_send(const char *buf, size_t len, PurpleXfer *xfer)
101
info = (ft_info *) xfer->data;
102
return send(info->sender_fd, buf, len, 0);
106
static ssize_t _qq_xfer_udp_send(const guint8 *buf, size_t len, PurpleXfer *xfer)
108
struct sockaddr_in sin;
111
info = (ft_info *) xfer->data;
112
memset(&sin, 0, sizeof(sin));
113
sin.sin_family = AF_INET;
114
if (!_qq_in_same_lan(info)) {
115
sin.sin_port = g_htons(info->remote_major_port);
116
sin.sin_addr.s_addr = g_htonl(info->remote_internet_ip);
117
} else if (info->use_major) {
118
sin.sin_port = g_htons(info->remote_major_port);
119
sin.sin_addr.s_addr = g_htonl(info->remote_real_ip);
121
sin.sin_port = g_htons(info->remote_minor_port);
122
sin.sin_addr.s_addr = g_htonl(info->remote_real_ip);
124
purple_debug_info("QQ", "sending to channel: %s:%d\n",
125
inet_ntoa(sin.sin_addr),
126
(int)g_ntohs(sin.sin_port)
128
return sendto(info->sender_fd, buf, len, 0, (struct sockaddr *) &sin, sizeof(sin));
131
/* user-defined functions for purple_xfer_read and purple_xfer_write */
134
static ssize_t _qq_xfer_read(char **buf, PurpleXfer *xfer)
136
*buf = g_newa(char, QQ_FILE_FRAGMENT_MAXLEN + 100);
137
return _qq_xfer_udp_recv(*buf, QQ_FILE_FRAGMENT_MAXLEN + 100, xfer);
141
gssize _qq_xfer_write(const guint8 *buf, size_t len, PurpleXfer *xfer)
143
return _qq_xfer_udp_send(buf, len, xfer);
146
static void _qq_xfer_recv_packet(gpointer data, gint source, PurpleInputCondition condition)
148
PurpleXfer *xfer = (PurpleXfer *) data;
149
PurpleAccount *account = purple_xfer_get_account(xfer);
150
PurpleConnection *gc = purple_account_get_connection(account);
153
/* FIXME: It seems that the transfer never use a packet
154
* larger than 1500 bytes, so if it happened to be a
155
* larger packet, either error occurred or protocol should
160
g_return_if_fail (source == info->recv_fd);
161
buf = g_newa(guint8, 1500);
162
size = _qq_xfer_udp_recv(buf, 1500, xfer);
163
qq_process_recv_file(gc, buf, size);
166
/* start file transfer process */
168
static void _qq_xfer_send_start (PurpleXfer *xfer)
170
PurpleAccount *account;
171
PurpleConnection *gc;
174
account = purple_xfer_get_account(xfer);
175
gc = purple_account_get_connection(account);
176
info = (ft_info *) xfer->data;
181
static void _qq_xfer_send_ack (PurpleXfer *xfer, const char *buffer, size_t len)
183
PurpleAccount *account;
184
PurpleConnection *gc;
186
account = purple_xfer_get_account(xfer);
187
gc = purple_account_get_connection(account);
188
qq_process_recv_file(gc, (guint8 *) buffer, len);
193
static void _qq_xfer_recv_start(PurpleXfer *xfer)
198
static void _qq_xfer_end(PurpleXfer *xfer)
201
g_return_if_fail(xfer != NULL && xfer->data != NULL);
202
info = (ft_info *) xfer->data;
204
qq_xfer_close_file(xfer);
205
if (info->dest_fp != NULL) {
206
fclose(info->dest_fp);
207
purple_debug_info("QQ", "file closed\n");
209
if (info->major_fd != 0) {
210
close(info->major_fd);
211
purple_debug_info("QQ", "major port closed\n");
213
if (info->minor_fd != 0) {
214
close(info->minor_fd);
215
purple_debug_info("QQ", "minor port closed\n");
218
if (info->buffer != NULL) {
219
munmap(info->buffer, purple_xfer_get_size(xfer));
220
purple_debug_info("QQ", "file mapping buffer is freed.\n");
226
static void qq_show_conn_info(ft_info *info)
228
gchar *internet_ip_str, *real_ip_str;
231
ip = g_htonl(info->remote_real_ip);
232
real_ip_str = gen_ip_str((guint8 *) &ip);
233
ip = g_htonl(info->remote_internet_ip);
234
internet_ip_str = gen_ip_str((guint8 *) &ip);
235
purple_debug_info("QQ", "remote internet ip[%s:%d], major port[%d], real ip[%s], minor port[%d]\n",
236
internet_ip_str, info->remote_internet_port,
237
info->remote_major_port, real_ip_str, info->remote_minor_port
240
g_free(internet_ip_str);
243
#define QQ_CONN_INFO_LEN 61
244
gint qq_get_conn_info(ft_info *info, guint8 *data)
247
/* 16 + 30 + 1 + 4 + 2 + 2 + 4 + 2 = 61 */
248
bytes += qq_getdata(info->file_session_key, 16, data + bytes);
249
bytes += 30; /* skip 30 bytes */
250
bytes += qq_get8(&info->conn_method, data + bytes);
251
bytes += qq_get32(&info->remote_internet_ip, data + bytes);
252
bytes += qq_get16(&info->remote_internet_port, data + bytes);
253
bytes += qq_get16(&info->remote_major_port, data + bytes);
254
bytes += qq_get32(&info->remote_real_ip, data + bytes);
255
bytes += qq_get16(&info->remote_minor_port, data + bytes);
256
qq_show_conn_info(info);
260
gint qq_fill_conn_info(guint8 *raw_data, ft_info *info)
263
/* 064: connection method, UDP 0x00, TCP 0x03 */
264
bytes += qq_put8 (raw_data + bytes, info->conn_method);
265
/* 065-068: outer ip address of sender (proxy address) */
266
bytes += qq_put32 (raw_data + bytes, info->local_internet_ip);
267
/* 069-070: sender port */
268
bytes += qq_put16 (raw_data + bytes, info->local_internet_port);
269
/* 071-072: the first listening port(TCP doesn't have this part) */
270
bytes += qq_put16 (raw_data + bytes, info->local_major_port);
271
/* 073-076: real ip */
272
bytes += qq_put32 (raw_data + bytes, info->local_real_ip);
273
/* 077-078: the second listening port */
274
bytes += qq_put16 (raw_data + bytes, info->local_minor_port);
279
/* fill in the common information of file transfer */
280
static gint _qq_create_packet_file_header
281
(guint8 *raw_data, UID to_uid, guint16 message_type, qq_data *qd, gboolean seq_ack)
290
if (!seq_ack) seq = qd->send_seq;
292
info = (ft_info *) qd->xfer->data;
293
seq = info->send_seq;
296
/* 000-003: receiver uid */
297
bytes += qq_put32 (raw_data + bytes, qd->uid);
298
/* 004-007: sender uid */
299
bytes += qq_put32 (raw_data + bytes, to_uid);
300
/* 008-009: sender client version */
301
bytes += qq_put16 (raw_data + bytes, qd->client_tag);
302
/* 010-013: receiver uid */
303
bytes += qq_put32 (raw_data + bytes, qd->uid);
304
/* 014-017: sender uid */
305
bytes += qq_put32 (raw_data + bytes, to_uid);
306
/* 018-033: md5 of (uid+session_key) */
307
bytes += qq_putdata (raw_data + bytes, qd->session_md5, 16);
308
/* 034-035: message type */
309
bytes += qq_put16 (raw_data + bytes, message_type);
310
/* 036-037: sequence number */
311
bytes += qq_put16 (raw_data + bytes, seq);
312
/* 038-041: send time */
313
bytes += qq_put32 (raw_data + bytes, (guint32) now);
314
/* 042-042: always 0x00 */
315
bytes += qq_put8 (raw_data + bytes, 0x00);
316
/* 043-043: sender icon */
317
bytes += qq_put8 (raw_data + bytes, qd->my_icon);
318
/* 044-046: always 0x00 */
319
bytes += qq_put16 (raw_data + bytes, 0x0000);
320
bytes += qq_put8 (raw_data + bytes, 0x00);
321
/* 047-047: we use font attr */
322
bytes += qq_put8 (raw_data + bytes, 0x01);
323
/* 048-051: always 0x00 */
324
bytes += qq_put32 (raw_data + bytes, 0x00000000);
326
/* 052-062: always 0x00 */
327
bytes += qq_put32 (raw_data + bytes, 0x00000000);
328
bytes += qq_put32 (raw_data + bytes, 0x00000000);
329
bytes += qq_put16 (raw_data + bytes, 0x0000);
330
bytes += qq_put8 (raw_data + bytes, 0x00);
331
/* 063: transfer_type, 0x65: FILE 0x6b: FACE */
332
bytes += qq_put8 (raw_data + bytes, QQ_FILE_TRANSFER_FILE); /* FIXME */
338
in_addr_t get_real_ip()
341
struct hostent *host;
343
gethostname(hostname, sizeof(hostname));
344
host = gethostbyname(hostname);
345
return *(host->h_addr);
349
#include <sys/ioctl.h>
352
#define MAXINTERFACES 16
353
in_addr_t get_real_ip()
357
struct ifreq buf[MAXINTERFACES];
360
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) return 0;
361
ifc.ifc_len = sizeof(buf);
362
ifc.ifc_buf = (caddr_t) buf;
363
if (ioctl(fd, SIOCGIFCONF, (char *) &ifc) < 0) return 0;
364
intrface = ifc.ifc_len / sizeof(struct ifreq);
365
for (i = 0; i < intrface; i++) {
366
/* buf[intrface].ifr_name */
367
if (ioctl(fd, SIOCGIFADDR, (char *) &buf[i]) >= 0)
369
ret = (((struct sockaddr_in *)(&buf[i].ifr_addr))->sin_addr).s_addr;
370
if (ret == g_ntohl(0x7f000001)) continue;
378
static void _qq_xfer_init_socket(PurpleXfer *xfer)
380
gint sockfd, listen_port = 0, i;
382
struct sockaddr_in sin;
385
g_return_if_fail(xfer != NULL);
386
g_return_if_fail(xfer->data != NULL);
387
info = (ft_info *) xfer->data;
390
info->local_real_ip = 0x7f000001;
392
info->local_real_ip = g_ntohl(inet_addr(purple_network_get_my_ip(-1)));
393
purple_debug_info("QQ", "local real ip is %x\n", info->local_real_ip);
395
for (i = 0; i < 2; i++) {
396
sockfd = socket(PF_INET, SOCK_DGRAM, 0);
397
g_return_if_fail(sockfd >= 0);
399
memset(&sin, 0, sizeof(sin));
400
sin.sin_family = AF_INET;
402
sin.sin_addr.s_addr = INADDR_ANY;
403
sin_len = sizeof(sin);
404
bind(sockfd, (struct sockaddr *) &sin, sin_len);
405
getsockname(sockfd, (struct sockaddr *) &sin, &sin_len);
406
listen_port = g_ntohs(sin.sin_port);
410
info->local_major_port = listen_port;
411
info->major_fd = sockfd;
412
purple_debug_info("QQ", "UDP Major Channel created on port[%d]\n",
413
info->local_major_port);
416
info->local_minor_port = listen_port;
417
info->minor_fd = sockfd;
418
purple_debug_info("QQ", "UDP Minor Channel created on port[%d]\n",
419
info->local_minor_port);
424
if (_qq_in_same_lan(info)) {
425
info->sender_fd = info->recv_fd = info->minor_fd;
427
info->sender_fd = info->recv_fd = info->major_fd;
429
/* xfer->watcher = purple_input_add(info->recv_fd, PURPLE_INPUT_READ, _qq_xfer_recv_packet, xfer); */
432
/* create the QQ_FILE_TRANS_REQ packet with file infomations */
433
static void _qq_send_packet_file_request (PurpleConnection *gc, UID to_uid, gchar *filename, gint filesize)
438
gint filename_len, filelen_strlen, packet_len, bytes;
441
qd = (qq_data *) gc->proto_data;
443
info = g_new0(ft_info, 1);
444
info->to_uid = to_uid;
445
info->send_seq = qd->send_seq;
446
info->local_internet_ip = qd->my_ip.s_addr;
447
info->local_internet_port = qd->my_port;
448
info->local_real_ip = 0x00000000;
449
info->conn_method = 0x00;
450
qd->xfer->data = info;
452
filename_len = strlen(filename);
453
filelen_str = g_strdup_printf("%d ?ֽ?", filesize);
454
filelen_strlen = strlen(filelen_str);
456
packet_len = 82 + filename_len + filelen_strlen;
457
raw_data = g_newa(guint8, packet_len);
460
bytes += _qq_create_packet_file_header(raw_data + bytes, to_uid,
461
QQ_FILE_TRANS_REQ, qd, FALSE);
462
bytes += qq_fill_conn_info(raw_data + bytes, info);
464
bytes += qq_put8 (raw_data + bytes, 0x20);
466
bytes += qq_put8 (raw_data + bytes, 0x1f);
467
/* undetermined len: filename */
468
bytes += qq_putdata (raw_data + bytes, (guint8 *) filename, filename_len);
470
bytes += qq_put8 (raw_data + bytes, 0x1f);
472
bytes += qq_putdata (raw_data + bytes, (guint8 *) filelen_str, filelen_strlen);
474
if (packet_len == bytes)
475
qq_send_cmd(gc, QQ_CMD_SEND_IM, raw_data, bytes);
477
purple_debug_info("qq_send_packet_file_request",
478
"%d bytes expected but got %d bytes\n",
481
g_free (filelen_str);
484
/* tell the buddy we want to accept the file */
485
static void _qq_send_packet_file_accept(PurpleConnection *gc, UID to_uid)
491
gint packet_len, bytes;
494
qd = (qq_data *) gc->proto_data;
495
info = (ft_info *) qd->xfer->data;
497
purple_debug_info("QQ", "I've accepted the file transfer request from %d\n", to_uid);
498
_qq_xfer_init_socket(qd->xfer);
501
raw_data = g_newa (guint8, packet_len);
504
minor_port = info->local_minor_port;
505
real_ip = info->local_real_ip;
506
info->local_minor_port = 0;
507
info->local_real_ip = 0;
509
bytes += _qq_create_packet_file_header(raw_data + bytes, to_uid, QQ_FILE_TRANS_ACC_UDP, qd, TRUE);
510
bytes += qq_fill_conn_info(raw_data + bytes, info);
512
info->local_minor_port = minor_port;
513
info->local_real_ip = real_ip;
515
if (packet_len == bytes)
516
qq_send_cmd(gc, QQ_CMD_SEND_IM, raw_data, bytes);
518
purple_debug_info("qq_send_packet_file_accept",
519
"%d bytes expected but got %d bytes\n",
523
static void _qq_send_packet_file_notifyip(PurpleConnection *gc, UID to_uid)
529
gint packet_len, bytes;
531
qd = (qq_data *) gc->proto_data;
536
raw_data = g_newa (guint8, packet_len);
539
purple_debug_info("QQ", "<== sending qq file notify ip packet\n");
540
bytes += _qq_create_packet_file_header(raw_data + bytes, to_uid, QQ_FILE_TRANS_NOTIFY, qd, TRUE);
541
bytes += qq_fill_conn_info(raw_data + bytes, info);
542
if (packet_len == bytes)
543
qq_send_cmd(gc, QQ_CMD_SEND_IM, raw_data, bytes);
545
purple_debug_info("qq_send_packet_file_notify",
546
"%d bytes expected but got %d bytes\n",
549
if (xfer->watcher) purple_input_remove(xfer->watcher);
550
xfer->watcher = purple_input_add(info->recv_fd, PURPLE_INPUT_READ, _qq_xfer_recv_packet, xfer);
551
purple_input_add(info->major_fd, PURPLE_INPUT_READ, _qq_xfer_recv_packet, xfer);
554
/* tell the buddy we don't want the file */
555
static void _qq_send_packet_file_reject (PurpleConnection *gc, UID to_uid)
559
gint packet_len, bytes;
561
purple_debug_info("_qq_send_packet_file_reject", "start\n");
562
qd = (qq_data *) gc->proto_data;
565
raw_data = g_newa (guint8, packet_len);
568
bytes += _qq_create_packet_file_header(raw_data + bytes, to_uid, QQ_FILE_TRANS_DENY_UDP, qd, TRUE);
570
if (packet_len == bytes)
571
qq_send_cmd(gc, QQ_CMD_SEND_IM, raw_data, bytes);
573
purple_debug_info("qq_send_packet_file",
574
"%d bytes expected but got %d bytes\n",
578
/* tell the buddy to cancel transfer */
579
static void _qq_send_packet_file_cancel (PurpleConnection *gc, UID to_uid)
583
gint packet_len, bytes;
585
purple_debug_info("_qq_send_packet_file_cancel", "start\n");
586
qd = (qq_data *) gc->proto_data;
589
raw_data = g_newa (guint8, packet_len);
592
purple_debug_info("_qq_send_packet_file_cancel", "before create header\n");
593
bytes += _qq_create_packet_file_header(raw_data + bytes, to_uid, QQ_FILE_TRANS_CANCEL, qd, TRUE);
594
purple_debug_info("_qq_send_packet_file_cancel", "end create header\n");
596
if (packet_len == bytes) {
597
purple_debug_info("_qq_send_packet_file_cancel", "before send cmd\n");
598
qq_send_cmd(gc, QQ_CMD_SEND_IM, raw_data, bytes);
601
purple_debug_info("qq_send_packet_file",
602
"%d bytes expected but got %d bytes\n",
605
purple_debug_info("qq_send_packet_file_cancel", "end\n");
608
/* request to send a file */
610
_qq_xfer_init (PurpleXfer * xfer)
612
PurpleConnection *gc;
613
PurpleAccount *account;
615
const gchar *filename;
616
gchar *base_filename;
618
g_return_if_fail (xfer != NULL);
619
account = purple_xfer_get_account(xfer);
620
gc = purple_account_get_connection(account);
622
to_uid = purple_name_to_uid (xfer->who);
623
g_return_if_fail (to_uid != 0);
625
filename = purple_xfer_get_local_filename (xfer);
626
g_return_if_fail (filename != NULL);
628
base_filename = g_path_get_basename(filename);
630
_qq_send_packet_file_request (gc, to_uid, base_filename,
631
purple_xfer_get_size(xfer));
632
g_free(base_filename);
635
/* cancel the transfer of receiving files */
636
static void _qq_xfer_cancel(PurpleXfer *xfer)
638
PurpleConnection *gc;
639
PurpleAccount *account;
641
g_return_if_fail (xfer != NULL);
642
account = purple_xfer_get_account(xfer);
643
gc = purple_account_get_connection(account);
645
switch (purple_xfer_get_status(xfer)) {
646
case PURPLE_XFER_STATUS_CANCEL_LOCAL:
647
_qq_send_packet_file_cancel(gc, purple_name_to_uid(xfer->who));
649
case PURPLE_XFER_STATUS_CANCEL_REMOTE:
650
_qq_send_packet_file_cancel(gc, purple_name_to_uid(xfer->who));
652
case PURPLE_XFER_STATUS_NOT_STARTED:
654
case PURPLE_XFER_STATUS_UNKNOWN:
655
_qq_send_packet_file_reject(gc, purple_name_to_uid(xfer->who));
657
case PURPLE_XFER_STATUS_DONE:
659
case PURPLE_XFER_STATUS_ACCEPTED:
661
case PURPLE_XFER_STATUS_STARTED:
666
/* init the transfer of receiving files */
667
static void _qq_xfer_recv_init(PurpleXfer *xfer)
669
PurpleConnection *gc;
670
PurpleAccount *account;
672
g_return_if_fail(xfer != NULL);
673
account = purple_xfer_get_account(xfer);
674
gc = purple_account_get_connection(account);
676
_qq_send_packet_file_accept(gc, purple_name_to_uid(xfer->who));
679
/* process reject im for file transfer request */
680
void qq_process_recv_file_reject (guint8 *data, gint data_len,
681
UID sender_uid, PurpleConnection *gc)
683
gchar *msg, *filename;
686
g_return_if_fail (data != NULL && data_len != 0);
687
qd = (qq_data *) gc->proto_data;
688
g_return_if_fail (qd->xfer != NULL);
690
/* border has been checked before
691
if (*cursor >= (data + data_len - 1)) {
692
purple_debug_warning("QQ",
693
"Received file reject message is empty\n");
697
filename = g_path_get_basename(purple_xfer_get_local_filename(qd->xfer));
698
msg = g_strdup_printf(_("%d has declined the file %s"),
699
sender_uid, filename);
701
purple_notify_warning (gc, _("File Send"), msg, NULL);
702
purple_xfer_request_denied(qd->xfer);
709
/* process cancel im for file transfer request */
710
void qq_process_recv_file_cancel (guint8 *data, gint data_len,
711
UID sender_uid, PurpleConnection *gc)
713
gchar *msg, *filename;
716
g_return_if_fail (data != NULL && data_len != 0);
717
qd = (qq_data *) gc->proto_data;
718
g_return_if_fail (qd->xfer != NULL
719
&& purple_xfer_get_filename(qd->xfer) != NULL);
721
/* border has been checked before
722
if (*cursor >= (data + data_len - 1)) {
723
purple_debug_warning("QQ", "Received file reject message is empty\n");
727
filename = g_path_get_basename(purple_xfer_get_local_filename(qd->xfer));
728
msg = g_strdup_printf
729
(_("%d cancelled the transfer of %s"),
730
sender_uid, filename);
732
purple_notify_warning (gc, _("File Send"), msg, NULL);
733
purple_xfer_cancel_remote(qd->xfer);
740
/* process accept im for file transfer request */
741
void qq_process_recv_file_accept(guint8 *data, gint data_len, UID sender_uid, PurpleConnection *gc)
748
g_return_if_fail (data != NULL && data_len != 0);
749
qd = (qq_data *) gc->proto_data;
751
info = (ft_info *) xfer->data;
753
if (data_len <= 30 + QQ_CONN_INFO_LEN) {
754
purple_debug_warning("QQ", "Received file reject message is empty\n");
758
bytes = 18 + 12; /* skip 30 bytes */
759
qq_get_conn_info(info, data + bytes);
760
_qq_xfer_init_socket(xfer);
762
_qq_xfer_init_udp_channel(info);
763
_qq_send_packet_file_notifyip(gc, sender_uid);
766
/* process request from buddy's im for file transfer request */
767
void qq_process_recv_file_request(guint8 *data, gint data_len, UID sender_uid, PurpleConnection * gc)
771
gchar *sender_name, **fileinfo;
777
g_return_if_fail (data != NULL && data_len != 0);
778
qd = (qq_data *) gc->proto_data;
780
info = g_newa(ft_info, 1);
781
info->local_internet_ip = qd->my_ip.s_addr;
782
info->local_internet_port = qd->my_port;
783
info->local_real_ip = 0x00000000;
784
info->to_uid = sender_uid;
786
if (data_len <= 2 + 30 + QQ_CONN_INFO_LEN) {
787
purple_debug_warning("QQ", "Received file request message is empty\n");
791
bytes += qq_get16(&(info->send_seq), data + bytes);
793
bytes += 18 + 12; /* skip 30 bytes */
794
bytes += qq_get_conn_info(info, data + bytes);
796
fileinfo = g_strsplit((gchar *) (data + 81 + 12), "\x1f", 2);
797
g_return_if_fail (fileinfo != NULL && fileinfo[0] != NULL && fileinfo[1] != NULL);
799
sender_name = uid_to_purple_name(sender_uid);
801
/* FACE from IP detector, ignored by gfhuang */
802
if(g_ascii_strcasecmp(fileinfo[0], "FACE") == 0) {
803
purple_debug_warning("QQ",
804
"Received a FACE ip detect from %d, so he/she must be online :)\n", sender_uid);
806
b = purple_find_buddy(gc->account, sender_name);
807
bd = (b == NULL) ? NULL : purple_buddy_get_protocol_data(b);
809
if(0 != info->remote_real_ip) {
810
g_memmove(&(bd->ip), &info->remote_real_ip, sizeof(bd->ip));
811
bd->port = info->remote_minor_port;
813
else if (0 != info->remote_internet_ip) {
814
g_memmove(&(bd->ip), &info->remote_internet_ip, sizeof(bd->ip));
815
bd->port = info->remote_major_port;
818
if(!is_online(bd->status)) {
819
bd->status = QQ_BUDDY_ONLINE_INVISIBLE;
820
bd->last_update = time(NULL);
821
qq_update_buddy_status(gc, bd->uid, bd->status, bd->comm_flag);
824
purple_debug_info("QQ", "buddy %d is already online\n", sender_uid);
828
purple_debug_warning("QQ", "buddy %d is not in list\n", sender_uid);
831
g_strfreev(fileinfo);
835
xfer = purple_xfer_new(purple_connection_get_account(gc),
840
purple_xfer_set_filename(xfer, fileinfo[0]);
841
purple_xfer_set_size(xfer, atoi(fileinfo[1]));
843
purple_xfer_set_init_fnc(xfer, _qq_xfer_recv_init);
844
purple_xfer_set_request_denied_fnc(xfer, _qq_xfer_cancel);
845
purple_xfer_set_cancel_recv_fnc(xfer, _qq_xfer_cancel);
846
purple_xfer_set_end_fnc(xfer, _qq_xfer_end);
847
purple_xfer_set_write_fnc(xfer, _qq_xfer_write);
852
purple_xfer_request(xfer);
856
g_strfreev(fileinfo);
859
static void _qq_xfer_send_notify_ip_ack(gpointer data, gint source, PurpleInputCondition cond)
861
PurpleXfer *xfer = (PurpleXfer *) data;
862
PurpleAccount *account = purple_xfer_get_account(xfer);
863
PurpleConnection *gc = purple_account_get_connection(account);
864
ft_info *info = (ft_info *) xfer->data;
866
purple_input_remove(xfer->watcher);
867
xfer->watcher = purple_input_add(info->recv_fd, PURPLE_INPUT_READ, _qq_xfer_recv_packet, xfer);
868
qq_send_file_ctl_packet(gc, QQ_FILE_CMD_NOTIFY_IP_ACK, info->to_uid, 0);
870
info->use_major = TRUE;
871
qq_send_file_ctl_packet(gc, QQ_FILE_CMD_NOTIFY_IP_ACK, info->to_uid, 0);
872
info->use_major = FALSE;
876
void qq_process_recv_file_notify(guint8 *data, gint data_len,
877
UID sender_uid, PurpleConnection *gc)
884
g_return_if_fail (data != NULL && data_len != 0);
885
qd = (qq_data *) gc->proto_data;
888
info = (ft_info *) qd->xfer->data;
889
if (data_len <= 2 + 30 + QQ_CONN_INFO_LEN) {
890
purple_debug_warning("QQ", "Received file notify message is empty\n");
895
bytes += qq_get16(&(info->send_seq), data + bytes);
898
bytes += qq_get_conn_info(info, data + bytes);
900
_qq_xfer_init_udp_channel(info);
902
xfer->watcher = purple_input_add(info->sender_fd, PURPLE_INPUT_WRITE, _qq_xfer_send_notify_ip_ack, xfer);
905
/* temp placeholder until a working function can be implemented */
906
gboolean qq_can_receive_file(PurpleConnection *gc, const char *who)
911
void qq_send_file(PurpleConnection *gc, const char *who, const char *file)
916
qd = (qq_data *) gc->proto_data;
918
xfer = purple_xfer_new (gc->account, PURPLE_XFER_SEND,
922
purple_xfer_set_init_fnc (xfer, _qq_xfer_init);
923
purple_xfer_set_cancel_send_fnc (xfer, _qq_xfer_cancel);
924
purple_xfer_set_write_fnc(xfer, _qq_xfer_write);
927
purple_xfer_request(xfer);
932
static void qq_send_packet_request_key(PurpleConnection *gc, guint8 key)
934
qq_send_cmd(gc, QQ_CMD_REQUEST_KEY, &key, 1);
937
static void qq_process_recv_request_key(PurpleConnection *gc)