Statistics
| Branch: | Tag: | Revision:

root / modules / gadu_protocol / dcc / dcc-manager.cpp @ ea3566bd

History | View | Annotate | Download (14.6 kB)

1
/***************************************************************************
2
 *                                                                         *
3
 *   This program is free software; you can redistribute it and/or modify  *
4
 *   it under the terms of the GNU General Public License as published by  *
5
 *   the Free Software Foundation; either version 2 of the License, or     *
6
 *   (at your option) any later version.                                   *
7
 *                                                                         *
8
 ***************************************************************************/
9
10
#include <QtCore/QtGlobal>
11
12
#ifdef Q_OS_WIN
13
#include <winsock2.h>
14
#else
15
#include <arpa/inet.h>
16
#endif
17
18
#include "accounts/account.h"
19
#include "buddies/buddy.h"
20
#include "buddies/buddy-manager.h"
21
#include "configuration/configuration-file.h"
22
#include "contacts/contact.h"
23
#include "contacts/contact-manager.h"
24
#include "file-transfer/file-transfer-manager.h"
25
#include "gui/windows/message-dialog.h"
26
27
#include "debug.h"
28
#include "misc/misc.h"
29
30
#include "dcc/dcc-manager.h"
31
#include "dcc/dcc-socket-notifiers.h"
32
#include "file-transfer/gadu-file-transfer-handler.h"
33
#include "services/gadu-file-transfer-service.h"
34
#include "socket-notifiers/gadu-protocol-socket-notifiers.h"
35
#include "gadu-account-details.h"
36
#include "gadu-contact-details.h"
37
38
#include "gadu-protocol.h"
39
40
41
DccManager::DccManager(GaduProtocol *protocol) :
42
                QObject(protocol), Protocol(protocol), MainSocketNotifiers(0)
43
{
44
        kdebugf();
45
46
        setUpDcc();
47
48
        kdebugf2();
49
}
50
51
DccManager::~DccManager()
52
{
53
        kdebugf();
54
55
        closeDcc();
56
57
        kdebugf2();
58
}
59
60
void DccManager::setUpExternalAddress(gg_login_params &loginParams)
61
{
62
        bool haveExternalDcc = !DccExternalIP.isNull() && DccExternalPort > 1023;
63
        loginParams.external_addr = haveExternalDcc ? htonl(DccExternalIP.toIPv4Address()) : 0;
64
        loginParams.external_port = haveExternalDcc ? DccExternalPort : 0;
65
}
66
67
68
/*
69
void DccManager::mainConfigurationWindowCreated(MainConfigurationWindow *mainConfigurationWindow)
70
{
71
        QWidget *allowDCC = mainConfigurationWindow->widgetById("dcc/AllowDCC");
72
        QWidget *fileTransfers = mainConfigurationWindow->widgetById("dcc/fileTransfers");
73
        QWidget *ip = mainConfigurationWindow->widgetById("dcc/ip");
74
75
        connect(allowDCC, SIGNAL(toggled(bool)), fileTransfers, SLOT(setEnabled(bool)));
76
        connect(allowDCC, SIGNAL(toggled(bool)), ip, SLOT(setEnabled(bool)));
77
78
        QWidget *ipAutotetect = mainConfigurationWindow->widgetById("dcc/ipAutodetect");
79
        ipAddress = mainConfigurationWindow->widgetById("dcc/ipAddress");
80
        forwarding = dynamic_cast<QCheckBox *>(mainConfigurationWindow->widgetById("dcc/forwarding"));
81
        forwardingExternalIp = mainConfigurationWindow->widgetById("dcc/forwardingExternalIp");
82
        forwardingExternalPort = mainConfigurationWindow->widgetById("dcc/forwardingExternalPort");
83
        forwardingLocalPort = mainConfigurationWindow->widgetById("dcc/forwardingLocalPort");
84
85
        connect(forwarding, SIGNAL(toggled(bool)), forwardingExternalIp, SLOT(setEnabled(bool)));
86
        connect(forwarding, SIGNAL(toggled(bool)), forwardingExternalPort, SLOT(setEnabled(bool)));
87
        connect(forwarding, SIGNAL(toggled(bool)), forwardingLocalPort, SLOT(setEnabled(bool)));
88
89
        connect(ipAutotetect, SIGNAL(toggled(bool)), ipAddress, SLOT(setDisabled(bool)));
90
        connect(ipAutotetect, SIGNAL(toggled(bool)), this, SLOT(onIpAutotetectToggled(bool)));
91
}*/
92
93
void DccManager::setUpDcc()
94
{
95
        kdebugf();
96
97
        WaitingFileTransfers.clear();
98
99
        GaduAccountDetails *gaduAccountDetails = dynamic_cast<GaduAccountDetails *>(Protocol->account().details());
100
        if (!gaduAccountDetails)
101
                return;
102
103
        struct gg_dcc *socket = gg_dcc_socket_create(gaduAccountDetails->uin(), gaduAccountDetails->dccLocalPort());
104
        if (!socket)
105
        {
106
                kdebugmf(KDEBUG_NETWORK | KDEBUG_INFO, "Couldn't bind DCC socket.\n");
107
108
                // TODO: 0.6.6
109
                // MessageDialog::msg(tr("Couldn't create DCC socket.\nDirect connections disabled."), true, "Warning");
110
                kdebugf2();
111
                return;
112
        }
113
114
        MainSocketNotifiers = new DccSocketNotifiers(Protocol, this);
115
        SocketNotifiers = QList<DccSocketNotifiers *>();
116
117
        QHostAddress DCCIP;
118
        short int DCCPort;
119
120
        if (gaduAccountDetails->dccIpDetect())
121
                DCCIP.setAddress("255.255.255.255");
122
        else
123
                DCCIP = gaduAccountDetails->dccIP();
124
125
        QHostAddress ext_ip;
126
127
        bool forwarding = gaduAccountDetails->dccForwarding() && !gaduAccountDetails->dccExternalIP().isNull();
128
129
        DccExternalIP = forwarding ? ext_ip : QHostAddress();
130
        DccExternalPort = forwarding ? gaduAccountDetails->dccExternalPort() : 0;
131
132
        gg_dcc_ip = htonl(DCCIP.toIPv4Address());
133
        gg_dcc_port = socket->port;
134
135
        kdebugmf(KDEBUG_NETWORK | KDEBUG_INFO, "DCC_IP=%s DCC_PORT=%d\n", qPrintable(DCCIP.toString()), DCCPort);
136
137
        DccEnabled = true;
138
139
        connectSocketNotifiers(MainSocketNotifiers);
140
        MainSocketNotifiers->watchFor(socket);
141
142
        kdebugf2();
143
}
144
/*
145
void DccManager::onIpAutotetectToggled(bool toggled)
146
{
147
        forwarding->setEnabled(!toggled);
148
149
        if (toggled)
150
        {
151
                forwardingExternalIp->setEnabled(false);
152
                forwardingExternalPort->setEnabled(false);
153
                forwardingLocalPort->setEnabled(false);
154
        }
155
        else
156
        {
157
                forwardingExternalIp->setEnabled(forwarding->isChecked());
158
                forwardingExternalPort->setEnabled(forwarding->isChecked());
159
                forwardingLocalPort->setEnabled(forwarding->isChecked());
160
        }
161
}*/
162
163
void DccManager::configurationUpdated()
164
{
165
//                 GaduAccount *account = dynamic_cast<GaduAccount *>(Protocol->account());
166
//                 if (!account)
167
//                                 return;
168
//                 account->loadConfiguration(xml_config_file);
169
                
170
  
171
172
        // kadu->reconnect() ??
173
}
174
175
bool DccManager::dccEnabled() const
176
{
177
        return DccEnabled;
178
}
179
180
// void DccManager::timeout()
181
// {
182
        // TODO: change into notification
183
//         MessageDialog::msg(tr("Direct connection timeout!\nThe receiver doesn't support direct connections or\nboth machines are behind routers with NAT."), true, "Warning");
184
// }
185
186
void DccManager::closeDcc()
187
{
188
        kdebugf();
189
190
        gg_dcc_ip = 0;
191
        gg_dcc_port = 0;
192
        DccEnabled = false;
193
194
        kdebugf2();
195
}
196
197
void DccManager::connectSocketNotifiers(DccSocketNotifiers *notifiers)
198
{
199
        connect(notifiers, SIGNAL(destroyed(QObject *)),
200
                        this, SLOT(socketNotifiersDestroyed(QObject *)));
201
        connect(notifiers, SIGNAL(incomingConnection(struct gg_dcc *)),
202
                        this, SLOT(dccIncomingConnection(struct gg_dcc *)));
203
}
204
205
void DccManager::disconnectSocketNotifiers(DccSocketNotifiers *notifiers)
206
{
207
        disconnect(notifiers, SIGNAL(destroyed(QObject *)),
208
                        this, SLOT(socketNotifiersDestroyed(QObject *)));
209
        disconnect(notifiers, SIGNAL(incomingConnection(struct gg_dcc *)),
210
                        this, SLOT(dccIncomingConnection(struct gg_dcc *)));
211
}
212
213
void DccManager::socketNotifiersDestroyed(QObject *socketNotifiers)
214
{
215
        SocketNotifiers.removeAll(dynamic_cast<DccSocketNotifiers *>(socketNotifiers));
216
}
217
218
void DccManager::connectionRequestReceived(Contact contact)
219
{
220
        kdebugf();
221
222
        if (contact.isNull())
223
                return;
224
225
        GaduContactDetails *details = Protocol->gaduContactDetails(contact);
226
        if (!details)
227
                return;
228
229
        struct gg_dcc *dcc = gg_dcc_get_file(htonl(contact.address().toIPv4Address()), contact.port(), details->uin(), details->uin());
230
        if (!dcc)
231
                return;
232
233
        DccSocketNotifiers *dccSocketNotifiers = new DccSocketNotifiers(Protocol, this);
234
        SocketNotifiers << dccSocketNotifiers;
235
        connectSocketNotifiers(dccSocketNotifiers);
236
        dccSocketNotifiers->watchFor(dcc);
237
238
        kdebugf2();
239
}
240
241
bool DccManager::acceptConnection(unsigned int uin, unsigned int peerUin, unsigned int peerAddr)
242
{
243
        GaduAccountDetails *gaduAccountDetails = dynamic_cast<GaduAccountDetails *>(Protocol->account().details());
244
        if (!gaduAccountDetails)
245
                return false;
246
247
        Contact contact = ContactManager::instance()->byId(Protocol->account(), QString::number(peerUin));
248
        if (contact.isNull())
249
                return false;
250
251
        Buddy buddy = contact.ownerBuddy();
252
        if (uin != gaduAccountDetails->uin() || buddy.isAnonymous() || buddy.isNull())
253
        {
254
                kdebugm(KDEBUG_WARNING, "insane values: uin:%d peer_uin:%d\n", uin, peerUin);
255
                return false;
256
        }
257
258
        if (buddy.isIgnored())
259
        {
260
                kdebugm(KDEBUG_WARNING, "unbidden user: %d\n", peerUin);
261
                return false;
262
        }
263
264
        QHostAddress remoteAddress(ntohl(peerAddr));
265
266
        if (remoteAddress == contact.address())
267
                return true;
268
269
        kdebugm(KDEBUG_WARNING, "possible spoofing attempt from %s (uin:%d)\n", qPrintable(remoteAddress.toString()), peerUin);
270
271
        return MessageDialog::ask(narg(
272
                        tr("%1 is asking for direct connection but his/her\n"
273
                                "IP address (%2) differs from what GG server returned\n"
274
                                "as his/her IP address (%3). It may be spoofing\n"
275
                                "or he/she has port forwarding. Continue connection?"),
276
                        buddy.display(),
277
                        remoteAddress.toString(),
278
                        contact.address().toString()));
279
}
280
281
void DccManager::needIncomingFileTransferAccept(DccSocketNotifiers *socket)
282
{
283
        FileTransfer fileTransfer = FileTransfer::create();
284
        fileTransfer.setFileTransferAccount(Protocol->account());
285
        fileTransfer.setFileTransferContact(ContactManager::instance()->byId(Protocol->account(), QString::number(socket->peerUin()), true));
286
        fileTransfer.setTransferType(TypeReceive);
287
        FileTransferManager::instance()->addItem(fileTransfer);
288
289
        GaduFileTransferHandler *handler = new GaduFileTransferHandler(fileTransfer);
290
        fileTransfer.setHandler(handler);
291
292
        handler->setFileTransferNotifiers(socket);
293
        socket->setGaduFileTransferHandler(handler);
294
295
        emit Protocol->CurrentFileTransferService->incomingFileTransfer(fileTransfer);
296
}
297
298
GaduFileTransferHandler * DccManager::findFileTransferHandler(DccSocketNotifiers *notifiers)
299
{
300
        foreach (GaduFileTransferHandler *handler, WaitingFileTransfers)
301
        {
302
                UinType uin = Protocol->uin(handler->transfer().fileTransferContact());
303
                if (uin == notifiers->peerUin())
304
                {
305
                        disconnectSocketNotifiers(notifiers);
306
                        SocketNotifiers.removeAll(notifiers);
307
                        return handler;
308
                }
309
        }
310
311
        return 0;
312
}
313
314
void DccManager::handleEventDccNew(struct gg_event *e) {
315
        kdebugmf(KDEBUG_NETWORK | KDEBUG_INFO, "GG_EVENT_DCC_NEW\n");
316
317
        DccSocketNotifiers *newSocketNotifiers = new DccSocketNotifiers(Protocol, this);
318
        SocketNotifiers << newSocketNotifiers;
319
        connectSocketNotifiers(newSocketNotifiers);
320
        newSocketNotifiers->watchFor(e->event.dcc_new);
321
322
        e->event.dcc_new = 0;
323
}
324
325
void DccManager::handleEventDcc7New(struct gg_event *e)
326
{
327
        kdebugf();
328
329
        struct gg_dcc7 *dcc = e->event.dcc7_new;
330
/*
331
        if (!acceptConnection(dcc->uin, dcc->peer_uin, dcc->remote_addr))
332
        {
333
                gg_dcc7_reject(dcc, 0);
334
                gg_dcc7_free(dcc);
335
                return;
336
        }
337
*/
338
        switch (dcc->dcc_type)
339
        {
340
                case GG_DCC7_TYPE_FILE:
341
                {
342
//                         TODO: ZARAZ
343
                        DccSocketNotifiers *newSocketNotifiers = new DccSocketNotifiers(Protocol, this);
344
                        SocketNotifiers << newSocketNotifiers;
345
                        connectSocketNotifiers(newSocketNotifiers);
346
                        newSocketNotifiers->watchFor(e->event.dcc7_new);
347
                        needIncomingFileTransferAccept(newSocketNotifiers);
348
//                         file_transfer_manager->dcc7IncomingFileTransfer(new DccSocket(dcc));
349
                        break;
350
                }
351
352
                default:
353
                        gg_dcc7_reject(dcc, GG_DCC7_REJECT_USER);
354
                        gg_dcc7_free(dcc);
355
                        break;
356
        }
357
358
        kdebugf2();
359
}
360
361
void DccManager::handleEventDcc7Accept(struct gg_event *e)
362
{
363
        kdebugf();
364
365
        foreach (DccSocketNotifiers *socketNotifiers, SocketNotifiers)
366
        {
367
                if (socketNotifiers->Socket7 == e->event.dcc7_accept.dcc7)
368
                {
369
                        socketNotifiers->handleEventDcc7Accept(e);
370
                        return;
371
                }
372
        }
373
}
374
375
void DccManager::handleEventDcc7Reject(struct gg_event *e)
376
{
377
        kdebugf();
378
379
        foreach (DccSocketNotifiers *socketNotifiers, SocketNotifiers)
380
        {
381
                if (socketNotifiers->Socket7 == e->event.dcc7_accept.dcc7)
382
                {
383
                        socketNotifiers->handleEventDcc7Reject(e);
384
                        return;
385
                }
386
        }
387
}
388
389
void DccManager::handleEventDcc7Pending(struct gg_event *e)
390
{
391
        kdebugf();
392
393
        foreach (DccSocketNotifiers *socketNotifiers, SocketNotifiers)
394
        {
395
                socketNotifiers->handleEventDcc7Pending(e);
396
                return;
397
        }
398
}
399
400
void DccManager::handleEventDcc7Error(struct gg_event *e)
401
{
402
        kdebugf();
403
404
        foreach (DccSocketNotifiers *socketNotifiers, SocketNotifiers)
405
        {
406
//                 if (socketNotifiers->Socket7 == e->event.dcc7_error)
407
//                 {
408
//                         socketNotifiers->handleEventDcc7Error(e);
409
//                         return;
410
//                 }
411
        }
412
}
413
414
void DccManager::fileTransferHandlerDestroyed(QObject *object)
415
{
416
        GaduFileTransferHandler *handler = qobject_cast<GaduFileTransferHandler *>(object);
417
418
        if (handler)
419
                WaitingFileTransfers.removeAll(handler);
420
}
421
422
void DccManager::attachSendFileTransferSocket6(unsigned int uin, Contact contact, GaduFileTransferHandler *handler)
423
{
424
        kdebugf();
425
426
        if (contact.isNull())
427
                return;
428
429
        GaduContactDetails *details = Protocol->gaduContactDetails(contact);
430
        if (!details)
431
                return;
432
433
        int port = contact.port();
434
        if (port >= 10)
435
        {
436
                struct gg_dcc *socket = gg_dcc_send_file(htonl(contact.address().toIPv4Address()), port, uin, details->uin());
437
                if (socket)
438
                {
439
                        DccSocketNotifiers *fileTransferNotifiers = new DccSocketNotifiers(Protocol, this);
440
                        handler->setFileTransferNotifiers(fileTransferNotifiers);
441
                        fileTransferNotifiers->watchFor(socket);
442
                        return;
443
                }
444
        }
445
446
        kdebugmf(KDEBUG_INFO | KDEBUG_NETWORK, "needs callback\n");
447
448
// startTimeOut
449
        connect(handler, SIGNAL(destroyed(QObject *)), this, SLOT(fileTransferHandlerDestroyed(QObject *)));
450
        WaitingFileTransfers << handler;
451
        gg_dcc_request(Protocol->gaduSession(), details->uin());
452
}
453
454
void DccManager::attachSendFileTransferSocket7(unsigned int uin, Contact contact, GaduFileTransferHandler *handler)
455
{
456
        kdebugf();
457
458
        if (contact.isNull())
459
                return;
460
461
        GaduContactDetails *details = Protocol->gaduContactDetails(contact);
462
        if (!details)
463
                return;
464
465
        gg_dcc7 *dcc = gg_dcc7_send_file(Protocol->gaduSession(), details->uin(),
466
                        qPrintable(handler->transfer().localFileName()), unicode2cp(handler->transfer().localFileName()).data(), 0);
467
468
        if (dcc)
469
        {
470
                DccSocketNotifiers *fileTransferNotifiers = new DccSocketNotifiers(Protocol, this);
471
                handler->setFileTransferNotifiers(fileTransferNotifiers);
472
                handler->transfer().setTransferStatus(StatusWaitingForAccept);
473
                fileTransferNotifiers->watchFor(dcc);
474
475
                SocketNotifiers << fileTransferNotifiers;
476
        }
477
        else
478
                handler->socketNotAvailable();
479
}
480
481
void DccManager::attachSendFileTransferSocket(GaduFileTransferHandler *handler)
482
{
483
        Contact contact = handler->transfer().fileTransferContact();
484
        if (contact.isNull())
485
                return;
486
487
        GaduContactDetails *details = Protocol->gaduContactDetails(contact);
488
        if (!details)
489
                return;
490
491
        GaduAccountDetails *account = dynamic_cast<GaduAccountDetails *>(Protocol->account().details());
492
        if (!account)
493
                return;
494
495
        DccVersion version = (details->gaduProtocolVersion() & 0x0000ffff) >= 0x29
496
                ? Dcc7
497
                : Dcc6;
498
499
        switch (version)
500
        {
501
                case Dcc6:
502
                        attachSendFileTransferSocket6(account->uin(), contact, handler);
503
                        break;
504
505
                case Dcc7:
506
                        attachSendFileTransferSocket7(account->uin(), contact, handler);
507
                        break;
508
        }
509
}
510
511
/*void DccManager::getVoiceSocket(uint32_t ip, uint16_t port, UinType myUin, UinType peerUin, DccHandler *handler, bool request)
512
{
513
        kdebugf();
514
515
        if ((port >= 10) && !request)
516
        {
517
518
                struct gg_dcc *sock = gg_dcc_voice_chat(htonl(ip), port, myUin, peerUin);
519
520
                if (sock)
521
                {
522
                        DccSocket *result = new DccSocket(this, sock);
523
                        result->setHandler(handler);
524
                        return;
525
                }
526
        }
527
528
        startTimeout();
529
        requests.insert(peerUin, handler);
530
        Protocol->dccRequest(peerUin);
531
532
        kdebugf2();
533
}*/
534