1 /***************************************************************************
2 cdownloadmanager.cpp - description
3 -------------------
4 begin : Don Mai 16 2002
5 copyright : (C) 2002-2005 by Mathias Küster
6 email : mathen@users.berlios.de
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include "cdownloadmanager.h"
19
20 #include <stdio.h>
21 #include <math.h>
22
23 #include "dcobject.h"
24 #include "cconfig.h"
25 #include "core/cdir.h"
26 #include "core/cfile.h"
27 #include "cconnectionmanager.h"
28 #include "cdownloadqueue.h"
29 #include "core/clogfile.h"
30 #include "core/cmanager.h"
31 #include "cfilemanager.h"
32 #include "dclib.h"
33 #include "core/platform.h"
34 #include "csearchmanager.h"
35 #include "cutils.h"
36 #include "core/ccallback.h"
37 #include "core/cnetaddr.h"
38
39 extern "C" {
40 #include "gnulib/md5.h"
41 }
42
43 #ifdef WIN32
44 #include <winsock2.h>
45 #else
46 #include <unistd.h>
47 #include <stdlib.h>
48 #include <errno.h>
49 #endif
50
51 #define TEST_CHUNK_SIZE (10*1024)
52
53 /* search results by TTH are now returned in a set */
54 #include <set>
55 #include <list>
56
57 /** */
CDownloadManager()58 CDownloadManager::CDownloadManager()
59 {
60 m_nID = 0;
61 m_eShutdownState = essNONE;
62
63 m_tDownloadQueueTimeout = time(0);
64 m_tUpdateTransferTimeout = time(0);
65 m_tHubSearchTimeout = time(0);
66 m_tSearchTimeout = 0;
67 m_tLastRateExtra = time(0);
68 m_tWaitListCleaned = time(0);
69
70 m_pTransfersMutex = new CMutex();
71 m_pTransferList = new CStringList<CTransferObject>();
72 m_pBanListMutex = new CMutex();
73 m_pTransferBanList = new CStringList<DCTransferBanObject>();
74 m_pExtraSlotsMutex = new CMutex();
75 m_pExtraUserSlotList = new CList<CExtraUserSlot>();
76 m_pWaitListMutex = new CMutex();
77 m_pTransferWaitList = new CList<DCTransferWait>();
78 m_pSearchList = new CList<CMessageSearchResult>();
79 m_pSearchQueryList = new CList<CDCMessage>();
80
81 m_pDownloadQueue = new CDownloadQueue();
82
83 m_pCallback = 0;
84 }
85
86 /** */
~CDownloadManager()87 CDownloadManager::~CDownloadManager()
88 {
89 SetInstance(0);
90 CManager::Instance()->Remove( m_pCallback );
91 delete m_pCallback;
92 m_pCallback = 0;
93
94 delete m_pExtraUserSlotList;
95 m_pExtraUserSlotList = 0;
96
97 delete m_pExtraSlotsMutex;
98 m_pExtraSlotsMutex = 0;
99
100 delete m_pTransferList;
101 m_pTransferList = 0;
102
103 delete m_pTransfersMutex;
104 m_pTransfersMutex = 0;
105
106 delete m_pTransferWaitList;
107 m_pTransferWaitList = 0;
108
109 delete m_pWaitListMutex;
110 m_pWaitListMutex = 0;
111
112 delete m_pTransferBanList;
113 m_pTransferBanList = 0;
114
115 delete m_pBanListMutex;
116 m_pBanListMutex = 0;
117
118 delete m_pSearchList;
119 m_pSearchList = 0;
120
121 delete m_pSearchQueryList;
122 m_pSearchQueryList = 0;
123
124 delete m_pDownloadQueue;
125 m_pDownloadQueue = 0;
126 }
127
128 /** load the queue */
DLM_LoadQueue()129 int CDownloadManager::DLM_LoadQueue()
130 {
131 int err = -1;
132 CStringList<DCTransferQueueObject> * StringList = 0;
133
134 m_pDownloadQueue->pQueueMutex->Lock();
135 m_pDownloadQueue->pQueue->Clear();
136 m_pDownloadQueue->pChunksMutex->Lock();
137 m_pDownloadQueue->pChunkList->Clear();
138
139 if ( CConfig::Instance() )
140 err = CConfig::Instance()->LoadDCTra( m_pDownloadQueue->pQueue, m_pDownloadQueue->pChunkList );
141
142 // send all files over the callback function
143 if ( err == 0 )
144 {
145 while( m_pDownloadQueue->pQueue->Next( &StringList) )
146 {
147 DCTransferQueueObject * TransferObject = 0;
148
149 while( StringList->Next( &TransferObject) )
150 {
151 DCTransferFileObject * TransferFileObject = 0;
152
153 while( TransferObject->pTransferFileList.Next( &TransferFileObject) )
154 {
155 SendFileInfo( TransferObject, TransferFileObject );
156 }
157 }
158 }
159 }
160
161 m_pCallback = new CCallback0<CDownloadManager>( this, &CDownloadManager::Callback );
162
163 if ( CManager::Instance() )
164 CManager::Instance()->Add( m_pCallback );
165
166 m_pDownloadQueue->pChunksMutex->UnLock();
167 m_pDownloadQueue->pQueueMutex->UnLock();
168
169 return err;
170 }
171
172 /** save the queue */
DLM_SaveQueue()173 int CDownloadManager::DLM_SaveQueue()
174 {
175 int err = -1;
176
177 m_pDownloadQueue->pQueueMutex->Lock();
178 m_pDownloadQueue->pChunksMutex->Lock();
179
180 if ( CConfig::Instance() )
181 err = CConfig::Instance()->SaveDCTra( m_pDownloadQueue->pQueue, m_pDownloadQueue->pChunkList );
182
183 m_pDownloadQueue->pChunksMutex->UnLock();
184 m_pDownloadQueue->pQueueMutex->UnLock();
185
186 return err;
187 }
188
189 /** disconnect all transfers for a clean shutdown */
DLM_Shutdown()190 void CDownloadManager::DLM_Shutdown()
191 {
192 CTransferObject * TransferObject = 0;
193
194 // set shutdown state
195 m_eShutdownState = essSHUTDOWN;
196
197 SendLogInfo("Shutdown download manager ...\n");
198
199 m_pTransfersMutex->Lock();
200
201 DPRINTF("Running Transfers: %ld\n",m_pTransferList->Count());
202
203 while( m_pTransferList->Next( &TransferObject ) )
204 {
205 TransferObject->m_pTransfer->Disconnect(true);
206 }
207
208 m_pTransfersMutex->UnLock();
209 }
210
211 /** add a extra slot to the user */
DLM_AddUserSlot(CString nick,CString hubname,int slot,bool permanent)212 void CDownloadManager::DLM_AddUserSlot( CString nick, CString hubname, int slot, bool permanent )
213 {
214 CExtraUserSlot * ExtraUserSlot;
215
216 m_pExtraSlotsMutex->Lock();
217
218 ExtraUserSlot = 0;
219
220 while( (ExtraUserSlot=m_pExtraUserSlotList->Next(ExtraUserSlot)) != 0 )
221 {
222 if ( (ExtraUserSlot->sNick == nick) && (ExtraUserSlot->sHubName == hubname) )
223 {
224 if ( slot == 0 )
225 {
226 ExtraUserSlot->iSlots = slot;
227 }
228 else
229 {
230 ExtraUserSlot->iSlots += slot;
231 }
232 ExtraUserSlot->bPermanent = permanent;
233 break;
234 }
235 }
236
237 if ( ExtraUserSlot == 0 )
238 {
239 ExtraUserSlot = new CExtraUserSlot();
240 ExtraUserSlot->sNick = nick;
241 ExtraUserSlot->sHubName = hubname;
242 ExtraUserSlot->iSlots = slot;
243 ExtraUserSlot->bPermanent = permanent;
244
245 m_pExtraUserSlotList->Add(ExtraUserSlot);
246 }
247
248 SendSlotInfo(ExtraUserSlot);
249
250 if ( (ExtraUserSlot->iSlots == 0) && (!ExtraUserSlot->bPermanent) )
251 {
252 m_pExtraUserSlotList->Del(ExtraUserSlot);
253 }
254
255 m_pExtraSlotsMutex->UnLock();
256 }
257
258 /** */
DLM_TransferConnect(CString nick,CString hubname)259 bool CDownloadManager::DLM_TransferConnect( CString nick, CString hubname )
260 {
261 bool res = false;
262
263 m_pDownloadQueue->pQueueMutex->Lock();
264
265 DCTransferQueueObject * TransferObject = 0;
266
267 if ( (TransferObject = m_pDownloadQueue->GetUserTransferObject( nick, hubname, CString() )) != 0 )
268 {
269 TransferObject->tTimeout = 0;
270 res = true;
271 }
272
273 m_pDownloadQueue->pQueueMutex->UnLock();
274
275 return res;
276 }
277
278 /** */
DLM_TransferClose(ulonglong transferid)279 bool CDownloadManager::DLM_TransferClose( ulonglong transferid )
280 {
281 CTransferObject * TransferObject = 0;
282 bool res = false;
283
284 m_pTransfersMutex->Lock();
285
286 if ( m_pTransferList->Get( CString::number(transferid), &TransferObject ) == 0 )
287 {
288 TransferObject->m_pTransfer->Disconnect(true);
289 res = true;
290 }
291
292 m_pTransfersMutex->UnLock();
293
294 return res;
295 }
296
297 /** */
DLM_TransferSetRate(ulonglong transferid,ulonglong rate)298 bool CDownloadManager::DLM_TransferSetRate( ulonglong transferid, ulonglong rate )
299 {
300 CTransferObject * TransferObject = 0;
301 bool res = false;
302
303 m_pTransfersMutex->Lock();
304
305 if ( m_pTransferList->Get( CString::number(transferid), &TransferObject ) == 0 )
306 {
307 TransferObject->m_pTransfer->SetRate(rate);
308 res = true;
309 }
310
311 m_pTransfersMutex->UnLock();
312
313 return res;
314 }
315
316 /** */
DLM_TransferGetRate(ulonglong transferid,ulonglong & rate)317 bool CDownloadManager::DLM_TransferGetRate( ulonglong transferid, ulonglong & rate )
318 {
319 CTransferObject * TransferObject = 0;
320 bool res = false;
321
322 m_pTransfersMutex->Lock();
323
324 if ( m_pTransferList->Get( CString::number(transferid), &TransferObject ) == 0 )
325 {
326 rate = TransferObject->m_pTransfer->GetRate();
327 res = true;
328 }
329
330 m_pTransfersMutex->UnLock();
331
332 return res;
333 }
334
335 /** */
DLM_TransferDirection(ulonglong transferid)336 eDirection CDownloadManager::DLM_TransferDirection( ulonglong transferid )
337 {
338 CTransferObject * TransferObject = 0;
339 eDirection direction=edNONE;
340
341 m_pTransfersMutex->Lock();
342
343 if ( m_pTransferList->Get( CString::number(transferid), &TransferObject ) == 0 )
344 {
345 direction = TransferObject->m_pTransfer->GetSrcDirection();
346 }
347
348 m_pTransfersMutex->UnLock();
349
350 return direction;
351 }
352
353 /** */
DLM_QueueAdd(CString nick,CString hubname,CString hubhost,CString remotename,CString localname,CString localpath,CString localrootpath,eltMedium medium,ulonglong size,ulonglong startposition,ulonglong endposition,CString hash,bool multi)354 void CDownloadManager::DLM_QueueAdd( CString nick, CString hubname, CString hubhost,
355 CString remotename, CString localname,
356 CString localpath, CString localrootpath,
357 eltMedium medium, ulonglong size,
358 ulonglong startposition,
359 ulonglong endposition,
360 CString hash,
361 bool multi )
362 {
363 CDir dir;
364 CString sfile;
365 DCTransferQueueObject * TransferObject;
366 DCTransferFileObject * TransferFileObject = 0;
367 DCHubObject * HubObject;
368
369 /*
370 * Although this may not be the best place for this, dclib got stuck in a loop of
371 * get next chunk ... no more chunks when I tried to download a zero byte file.
372 * This will mean zero byte files are never present in the queue, they are just
373 * immediately created.
374 */
375 if ( (size == 0) && (medium == eltFILE) )
376 {
377 if ( startposition != 0 )
378 {
379 CString logmsg = "Warning: 0B file has non-zero start position of ";
380 logmsg += CString::number(startposition);
381 SendLogInfo( logmsg );
382 }
383
384 if ( endposition != 0 )
385 {
386 CString logmsg = "Warning: 0B file has non-zero end position of ";
387 logmsg += CString::number(endposition);
388 SendLogInfo( logmsg );
389 }
390
391 if ( localrootpath.IsEmpty() )
392 {
393 sfile = CConfig::Instance()->GetDownloadFinishedFolder();
394 if ( sfile.IsEmpty() )
395 {
396 sfile = CConfig::Instance()->GetDownloadFolder();
397 }
398 }
399 else
400 {
401 sfile = localrootpath;
402 }
403
404 localpath = localpath.Replace(':',"");
405 localname = localname.Replace(':',"");
406
407 sfile += '/';
408 sfile += localpath;
409 sfile += '/';
410
411 sfile = CDir::SimplePath(sfile);
412
413 if ( dir.IsDir( sfile, false ) == false )
414 {
415 if ( dir.CreatePath( sfile ) == false )
416 {
417 CString logmsg = "Create path '";
418 logmsg += sfile;
419 logmsg += "' for 0B file '";
420 logmsg += localname;
421 logmsg += "' failed";
422 SendLogInfo( logmsg );
423 return;
424 }
425 }
426
427 sfile += localname;
428
429 if ( dir.IsFile( sfile, false ) == false )
430 {
431 CFile cfile;
432 const int mode = IO_RAW | IO_READONLY | IO_CREAT;
433
434 /* From CTransfer::DoInitDownload() */
435 const int acc = MO_IRUSR|MO_IWUSR|MO_IRGRP|MO_IWGRP|MO_IROTH|MO_IWOTH;
436
437 if ( cfile.Open( sfile, mode, acc ) == false )
438 {
439 CString logmsg = "Create 0B file '";
440 logmsg += sfile;
441 logmsg += "' failed";
442 SendLogInfo( logmsg );
443 return;
444 }
445 else
446 {
447 cfile.Close();
448 }
449 }
450
451 /* Either already existed or has been created, send download finished message */
452
453 CString logmsg = "Transfer done '";
454 logmsg += remotename;
455 logmsg += '\'';
456 SendLogInfo( logmsg );
457
458 if ( CConfig::Instance()->GetLogFile() && CConfig::Instance()->GetLogFinishedDownloads() )
459 {
460 logmsg = "Transfer done '";
461 logmsg += sfile;
462 logmsg += '\'';
463 CLogFile::Write(CConfig::Instance()->GetLogFileName(),eltINFO,logmsg);
464 }
465
466 return;
467 }
468
469 /* this never happens anymore, fixed in 0.3.18, unless something was missed in valknut */
470 if ((hash.Left(4)).ToUpper() == "TTH:")
471 {
472 DPRINTF("DLM_QueueAdd: Removed TTH: prefix from TTH\n");
473 hash = hash.Mid(4, hash.Length() - 4);
474 }
475
476 /* DPRINTF("add queue entry: %s %s %s %s %d %s %s %s %llu %llu\n",
477 nick.Data(),
478 remotename.Data(),
479 hubname.Data(),
480 hubhost.Data(),
481 medium,
482 localname.Data(),
483 localpath.Data(),
484 localrootpath.Data(),
485 startposition,
486 size );*/
487
488 m_pDownloadQueue->pQueueMutex->Lock();
489
490 CStringList<DCTransferQueueObject> * StringList = m_pDownloadQueue->GetUserHubList( nick );
491
492 if ( (TransferObject = m_pDownloadQueue->GetUserTransferObject( nick, hubname, hubhost )) == 0 )
493 {
494 TransferObject = new DCTransferQueueObject();
495
496 TransferObject->sNick = nick;
497 TransferObject->sHubHost = hubhost;
498 TransferObject->sHubName = hubname;
499 TransferObject->eState = etwsIDLE;
500 TransferObject->iConnections = 0;
501 TransferObject->tTimeout = 0;
502
503 HubObject = new DCHubObject();
504
505 HubObject->m_sHubName = hubname;
506 HubObject->m_sHubHost = hubhost;
507 HubObject->m_bActive = true;
508
509 TransferObject->pHubList.Add(HubObject);
510
511 if ( StringList == 0 )
512 {
513 StringList = new CStringList<DCTransferQueueObject>();
514 m_pDownloadQueue->pQueue->Add( nick, StringList );
515 }
516
517 StringList->Add( hubname, TransferObject );
518
519 //DPRINTF("transfer add\n");
520 }
521 else
522 {
523 TransferFileObject = m_pDownloadQueue->GetUserFileObject( nick, hubname, hubhost, remotename );
524 }
525
526 // file not found for the nick/hub
527 if ( TransferFileObject == 0 )
528 {
529 TransferFileObject = new DCTransferFileObject();
530
531 TransferFileObject->m_eState = etfsNONE;
532 TransferFileObject->m_nSize = size;
533 TransferFileObject->m_bMulti = multi;
534 TransferFileObject->m_eMedium = medium;
535 TransferFileObject->m_sRemoteFile = remotename;
536 TransferFileObject->m_sHash = hash;
537
538 if ( remotename == DC_USER_FILELIST )
539 {
540 TransferFileObject->m_nPriority = 0;
541 TransferFileObject->m_sJumpTo = localpath;
542 localpath.Empty();
543 if ( localrootpath.NotEmpty() )
544 {
545 TransferFileObject->m_pDirList = new std::list<CString>();
546 TransferFileObject->m_pDirList->push_back( localrootpath );
547 localrootpath.Empty();
548 }
549 }
550 else
551 {
552 TransferFileObject->m_nPriority = 2;
553 }
554
555 if ( localrootpath.IsEmpty() )
556 {
557 sfile = CConfig::Instance()->GetDownloadFolder();
558 }
559 else
560 {
561 sfile = localrootpath;
562 }
563
564 localpath = localpath.Replace(':',"");
565 localname = localname.Replace(':',"");
566
567 sfile += '/';
568 sfile += localpath;
569 sfile += '/';
570 sfile += localname;
571 sfile = CDir::SimplePath(sfile);
572
573 TransferFileObject->m_sLocalFile = sfile;
574 TransferFileObject->m_sLocalPath = localpath;
575 TransferFileObject->m_sLocalFileName = localname;
576
577 TransferObject->pTransferFileList.Add( remotename, TransferFileObject );
578
579 //DPRINTF("file add '%s' %ld\n",sfile.Data(),TransferObject->pTransferFileList.Count());
580
581 m_pDownloadQueue->pChunksMutex->Lock();
582
583 DCFileChunkObject * FileChunkObject;
584
585 if ( remotename == DC_USER_FILELIST )
586 {
587 DPRINTF("no chunk for userlists\n");
588 }
589 else if ( m_pDownloadQueue->pChunkList->Get( sfile, &FileChunkObject ) != 0 )
590 {
591 FileChunkObject = new DCFileChunkObject();
592
593 FileChunkObject->m_sLocalFile = sfile;
594 FileChunkObject->m_sHash = hash;
595 FileChunkObject->m_bMulti = multi;
596 FileChunkObject->m_nSize = size;
597 FileChunkObject->m_nSizeDone = startposition;
598 FileChunkObject->m_nReferenceCount = 1;
599
600 // create the first unfinished chunk
601 DCChunkObject * ChunkObject = new DCChunkObject();
602 ChunkObject->m_nStart = startposition;
603 ChunkObject->m_nEnd = size;
604
605 if( endposition )
606 {
607 endposition++;
608 FileChunkObject->m_nSizeDone = size - (endposition - startposition);
609 ChunkObject->m_nEnd = endposition;
610 }
611
612 FileChunkObject->m_Chunks.Add(ChunkObject);
613 m_pDownloadQueue->pChunkList->Add( sfile, FileChunkObject );
614
615 //DPRINTF("add file chunk object\n");
616 }
617 else
618 {
619 FileChunkObject->m_nReferenceCount++;
620 DPRINTF("file chunk object found\n");
621
622 // fill in any missing information in case a source with TTH is
623 // added to a download without TTH
624 if ( (FileChunkObject->m_sHash.IsEmpty()) && (!hash.IsEmpty()) )
625 {
626 FileChunkObject->m_sHash = hash;
627
628 // we now need to iterate over the entire queue to fill in other missing TTHs for this local file
629 // how to iterate over the queue was taken from InitSearch
630 CStringList<DCTransferQueueObject> * sl = 0;
631
632 while ( m_pDownloadQueue->pQueue->Next( &sl ) )
633 {
634 DCTransferQueueObject * tqo = 0;
635
636 while ( sl->Next( &tqo ) )
637 {
638 DCTransferFileObject * tfo = 0;
639
640 while ( tqo->pTransferFileList.Next( &tfo ) )
641 {
642 if ( (tfo->m_sLocalFile == FileChunkObject->m_sLocalFile) && (tfo->m_sHash.IsEmpty()) )
643 {
644 tfo->m_sHash = hash;
645
646 // update GUI
647 SendFileInfo( tqo, tfo );
648 }
649 }
650 }
651 }
652 }
653
654 // fills in missing information from existing transfer
655 // if source without TTH is added to one with a TTH
656 if ( TransferFileObject->m_sHash.IsEmpty() )
657 {
658 TransferFileObject->m_sHash = FileChunkObject->m_sHash;
659 }
660 }
661
662 m_pDownloadQueue->pChunksMutex->UnLock();
663 }
664 else
665 {
666 DPRINTF("file found ...\n");
667
668 if ( remotename == DC_USER_FILELIST )
669 {
670 TransferFileObject->m_sJumpTo = localpath;
671 if ( localrootpath.NotEmpty() )
672 {
673 if ( TransferFileObject->m_pDirList )
674 {
675 // do not download a folder that is inside one already queued
676 // remove any folders that are inside this folder
677 std::list<CString>::iterator it = TransferFileObject->m_pDirList->begin();
678 while ( it != TransferFileObject->m_pDirList->end() )
679 {
680 if ( localrootpath.StartsWith( *it ) )
681 {
682 break;
683 }
684 else if ( it->StartsWith( localrootpath ) )
685 {
686 it = TransferFileObject->m_pDirList->erase( it );
687 }
688 else
689 {
690 ++it;
691 }
692 }
693
694 if ( it == TransferFileObject->m_pDirList->end() )
695 {
696 TransferFileObject->m_pDirList->push_back( localrootpath );
697 }
698 else
699 {
700 DPRINTF("'%s' already queued within '%s'\n",localrootpath.Data(),it->Data());
701 }
702 }
703 else
704 {
705 TransferFileObject->m_pDirList = new std::list<CString>();
706 TransferFileObject->m_pDirList->push_back( localrootpath );
707 }
708
709 //DPRINTF("directory queue now %zd\n",TransferFileObject->m_pDirList->size());
710 DPRINTF("directory queue now %lu\n",(unsigned long) TransferFileObject->m_pDirList->size());
711 }
712 }
713 }
714
715 SendFileInfo( TransferObject, TransferFileObject );
716
717 m_pDownloadQueue->pQueueMutex->UnLock();
718 }
719
720 /** 0: file not in the queue
721 1: file already in the queue by same nick and hub
722 2: local file with same TTH (same size if no TTH) already in the queue (multi download)
723 3: local file with same TTH (same size if no TTH) already in the queue without multi (no multi download)
724 4: local file with different TTH (different size if no TTH) already in the queue (multi download error)
725 */
DLM_QueueCheck(CString nick,CString hubname,CString hubhost,CString remotename,CString localname,CString localpath,CString localrootpath,eltMedium,ulonglong size,CString tth)726 int CDownloadManager::DLM_QueueCheck( CString nick, CString hubname, CString hubhost,
727 CString remotename, CString localname,
728 CString localpath, CString localrootpath,
729 eltMedium, ulonglong size, CString tth )
730 {
731 m_pDownloadQueue->pQueueMutex->Lock();
732
733 // this should really be fixed globally
734 if ( tth.Left(4).ToUpper() == "TTH:" )
735 {
736 tth = tth.Mid(4);
737 }
738
739 CDir dir;
740 CString sfile;
741 int res = 0;
742 DCTransferQueueObject * TransferObject;
743 DCTransferFileObject * TransferFileObject = 0;
744
745 if ( (TransferObject = m_pDownloadQueue->GetUserTransferObject( nick, hubname, hubhost )) != 0 )
746 {
747 if ( (TransferFileObject = m_pDownloadQueue->GetUserFileObject( nick, hubname, hubhost, remotename )) != 0 )
748 {
749 res = 1;
750 }
751 }
752
753 // check if a local file allready exist
754 if ( (res == 0) && (remotename != DC_USER_FILELIST) )
755 {
756 if ( localrootpath.IsEmpty() )
757 {
758 sfile = CConfig::Instance()->GetDownloadFolder();
759 }
760 else
761 {
762 sfile = localrootpath;
763 }
764
765 localpath = localpath.Replace(':',"");
766 localname = localname.Replace(':',"");
767
768 sfile += '/';
769 sfile += localpath;
770 sfile += '/';
771 sfile += localname;
772 sfile = CDir::SimplePath(sfile);
773
774 DCFileChunkObject * FileChunkObject;
775
776 m_pDownloadQueue->pChunksMutex->Lock();
777
778 if ( m_pDownloadQueue->pChunkList->Get( sfile, &FileChunkObject ) == 0 )
779 {
780 // allow manual addition of non-TTH sources to files with TTHs
781 // and allow addition of TTH sources to files with no TTH
782 if ( ((tth.IsEmpty() || FileChunkObject->m_sHash.IsEmpty()) && (FileChunkObject->m_nSize == size)) || (FileChunkObject->m_sHash == tth) )
783 {
784 if ( FileChunkObject->m_bMulti )
785 {
786 res = 2;
787 }
788 else
789 {
790 res = 3;
791 }
792 }
793 else
794 {
795 res = 4;
796 }
797 }
798
799 m_pDownloadQueue->pChunksMutex->UnLock();
800 }
801
802 m_pDownloadQueue->pQueueMutex->UnLock();
803
804 return res;
805 }
806
807 /** change the src-nick/hubname to dst-nick/hubname in the queue */
DLM_QueueEdit(CString srcnick,CString srchubname,CString dstnick,CString dsthubname,CString dsthubhost)808 bool CDownloadManager::DLM_QueueEdit( CString srcnick, CString srchubname, CString dstnick, CString dsthubname, CString dsthubhost )
809 {
810 bool res;
811 DCTransferQueueObject * TransferObject;
812 DCTransferFileObject * TransferFileObject;
813
814 m_pDownloadQueue->pQueueMutex->Lock();
815
816 res = false;
817
818 // check if transfer run
819 if ( (TransferObject = m_pDownloadQueue->GetUserTransferObject( srcnick, srchubname, CString() )) != 0 )
820 {
821 if ( (TransferObject->eState != etwsWAIT) &&
822 (TransferObject->eState != etwsRUN) )
823 {
824 // only rename if the new not exists
825 if ( m_pDownloadQueue->GetUserTransferObject( dstnick, dsthubname, dsthubhost ) == 0 )
826 {
827 // send remove all files
828 TransferFileObject = 0;
829
830 while( TransferObject->pTransferFileList.Next( &TransferFileObject ) )
831 {
832 SendFileInfo( TransferObject, TransferFileObject, true );
833 }
834
835 // rename old entry
836 m_pDownloadQueue->RenameNick( srcnick, dstnick, srchubname, dsthubname );
837
838 // get hubhost from new entry
839 if ( (TransferObject = m_pDownloadQueue->GetUserTransferObject( dstnick, dsthubname, dsthubhost )) != 0 )
840 {
841 TransferObject->sHubHost = dsthubhost;
842
843 // send new files
844 TransferFileObject = 0;
845
846 while( TransferObject->pTransferFileList.Next( &TransferFileObject ) )
847 {
848 SendFileInfo( TransferObject, TransferFileObject );
849 }
850
851 res = true;
852 }
853 }
854 else
855 {
856 // update hubhost
857 if ( TransferObject->sHubHost != dsthubhost )
858 {
859 TransferObject->sHubHost = dsthubhost;
860 SendFileInfo( TransferObject );
861 }
862
863 }
864 }
865 }
866
867 m_pDownloadQueue->pQueueMutex->UnLock();
868
869 return res;
870 }
871
872 /** */
DLM_QueuePause(CString nick,CString hubname,CString remotefile,bool pause)873 bool CDownloadManager::DLM_QueuePause( CString nick, CString hubname, CString remotefile, bool pause )
874 {
875 bool res = false;
876 DCTransferFileObject * TransferFileObject = 0;
877 DCTransferQueueObject * TransferObject = 0;
878
879 m_pDownloadQueue->pQueueMutex->Lock();
880
881 if ( (TransferObject = m_pDownloadQueue->GetUserTransferObject( nick, hubname, CString() )) != 0 )
882 {
883 if ( remotefile.NotEmpty() )
884 {
885 if ( (TransferFileObject = m_pDownloadQueue->GetUserFileObject( nick, hubname, CString(), remotefile )) != 0 )
886 {
887 if ( TransferFileObject->m_eState != etfsTRANSFER )
888 {
889 if ( pause )
890 TransferFileObject->m_eState = etfsPAUSE;
891 else
892 TransferFileObject->m_eState = etfsNONE;
893
894 SendFileInfo( TransferObject, TransferFileObject );
895 res = true;
896 }
897 }
898 }
899 else
900 {
901 TransferFileObject = 0;
902
903 while ( TransferObject->pTransferFileList.Next( &TransferFileObject ) )
904 {
905 if ( TransferFileObject->m_eState != etfsTRANSFER )
906 {
907 if ( pause )
908 TransferFileObject->m_eState = etfsPAUSE;
909 else
910 TransferFileObject->m_eState = etfsNONE;
911
912 SendFileInfo( TransferObject, TransferFileObject );
913 res = true;
914 }
915 }
916 }
917 }
918
919 m_pDownloadQueue->pQueueMutex->UnLock();
920
921 return res;
922 }
923
924 /** */
DLM_QueueRemove(CString nick,CString hubname,CString remotefile)925 bool CDownloadManager::DLM_QueueRemove( CString nick, CString hubname, CString remotefile )
926 {
927 bool res;
928
929 m_pDownloadQueue->pQueueMutex->Lock();
930
931 res = RemoveQueueFile( nick, hubname, remotefile );
932
933 m_pDownloadQueue->pQueueMutex->UnLock();
934
935 return res;
936 }
937
938 /** */
DLM_QueueRemove(CString localfile)939 bool CDownloadManager::DLM_QueueRemove( CString localfile )
940 {
941 bool res;
942
943 m_pDownloadQueue->pQueueMutex->Lock();
944
945 res = RemoveQueueFile(localfile);
946
947 m_pDownloadQueue->pQueueMutex->UnLock();
948
949 return res;
950 }
951
952 /** */
DLM_QueueRemoveDirectory(CString nick,CString hubname,CString directory)953 int CDownloadManager::DLM_QueueRemoveDirectory( CString nick, CString hubname, CString directory )
954 {
955 int res;
956
957 m_pDownloadQueue->pQueueMutex->Lock();
958
959 DCTransferFileObject * TransferFileObject = m_pDownloadQueue->GetUserFileObject( nick, hubname, CString(), DC_USER_FILELIST );
960
961 if ( TransferFileObject )
962 {
963 if ( TransferFileObject->m_pDirList )
964 {
965 std::list<CString>::iterator it = TransferFileObject->m_pDirList->begin();
966 for ( ; it != TransferFileObject->m_pDirList->end(); ++it )
967 {
968 if ( *it == directory )
969 {
970 break;
971 }
972 }
973
974 if ( it == TransferFileObject->m_pDirList->end() )
975 {
976 res = 3;
977 }
978 else
979 {
980 TransferFileObject->m_pDirList->erase( it );
981 if ( TransferFileObject->m_pDirList->empty() )
982 {
983 delete TransferFileObject->m_pDirList;
984 TransferFileObject->m_pDirList = 0;
985 }
986 res = 0;
987
988 DCTransferQueueObject * TransferQueueObject = m_pDownloadQueue->GetUserTransferObject( nick, hubname, CString() );
989 if ( TransferQueueObject )
990 {
991 SendFileInfo( TransferQueueObject, TransferFileObject );
992 }
993 }
994 }
995 else
996 {
997 res = 2;
998 }
999 }
1000 else
1001 {
1002 res = 1;
1003 }
1004
1005 m_pDownloadQueue->pQueueMutex->UnLock();
1006
1007 return res;
1008 }
1009
1010 /** */
DLM_QueueSetFilePriority(CString nick,CString hubname,CString remotefile,int priority)1011 bool CDownloadManager::DLM_QueueSetFilePriority( CString nick, CString hubname, CString remotefile, int priority )
1012 {
1013 m_pDownloadQueue->pQueueMutex->Lock();
1014
1015 bool res = false;
1016 DCTransferQueueObject * TransferObject = 0;
1017 DCTransferFileObject * TransferFileObject = 0;
1018
1019 if ( (TransferObject = m_pDownloadQueue->GetUserTransferObject( nick, hubname, CString() )) != 0 )
1020 {
1021 if ( (remotefile.NotEmpty()) && (priority <= MAX_FILE_PRIORITY) )
1022 {
1023 if ( (TransferFileObject = m_pDownloadQueue->GetUserFileObject( nick, hubname, CString(), remotefile )) != 0 )
1024 {
1025 // we don't need check if transfer is running
1026 TransferFileObject->m_nPriority = priority;
1027
1028 SendFileInfo( TransferObject, TransferFileObject );
1029
1030 res = true;
1031 }
1032 }
1033 }
1034
1035 m_pDownloadQueue->pQueueMutex->UnLock();
1036
1037 return res;
1038 }
1039
1040 /** */
DLM_QueueGetFileInfo(CString nick,CString hubname,CString hubhost,CString remotefile,CUserFileInfo * UserFileInfo)1041 bool CDownloadManager::DLM_QueueGetFileInfo( CString nick, CString hubname, CString hubhost, CString remotefile, CUserFileInfo * UserFileInfo )
1042 {
1043 bool res = false;
1044
1045 if (!UserFileInfo)
1046 {
1047 return res;
1048 }
1049
1050 m_pDownloadQueue->pQueueMutex->Lock();
1051
1052 DCTransferQueueObject * TransferObject;
1053 DCTransferFileObject * TransferFileObject;
1054
1055 if ( (TransferObject = m_pDownloadQueue->GetUserTransferObject( nick, hubname, hubhost )) != 0 )
1056 {
1057 UserFileInfo->eWaitState = TransferObject->eState;
1058
1059 if ( remotefile.NotEmpty() )
1060 {
1061 if ( TransferObject->pTransferFileList.Get( remotefile, &TransferFileObject ) == 0 )
1062 {
1063 UserFileInfo->eFileState = TransferFileObject->m_eState;
1064 UserFileInfo->sLocalFile = TransferFileObject->m_sLocalFile;
1065 UserFileInfo->bMulti = TransferFileObject->m_bMulti;
1066 res = true;
1067 }
1068 }
1069 else
1070 {
1071 res = true;
1072 }
1073 }
1074
1075 m_pDownloadQueue->pQueueMutex->UnLock();
1076
1077 return res;
1078 }
1079
1080 /** */
DLM_QueueGetFileChunk(CString file)1081 DCFileChunkObject * CDownloadManager::DLM_QueueGetFileChunk( CString file )
1082 {
1083 m_pDownloadQueue->pQueueMutex->Lock();
1084
1085 DCFileChunkObject * FileChunkObject1, * FileChunkObject2=0;
1086
1087 if ( (FileChunkObject1 = m_pDownloadQueue->GetFileChunkObject(file)) != 0 )
1088 {
1089 FileChunkObject2 = new DCFileChunkObject(FileChunkObject1);
1090 }
1091
1092 m_pDownloadQueue->pQueueMutex->UnLock();
1093
1094 return FileChunkObject2;
1095 }
1096
1097 /** */
DLM_QueueUpdateHub(CString nick,CString hubname)1098 bool CDownloadManager::DLM_QueueUpdateHub( CString nick, CString hubname )
1099 {
1100 m_pDownloadQueue->pQueueMutex->Lock();
1101
1102 bool res = false;
1103 DCConfigHubItem hubitem;
1104 DCTransferQueueObject * TransferObject;
1105
1106 if ( (TransferObject = m_pDownloadQueue->GetUserTransferObject( nick, hubname, CString() )) != 0 )
1107 {
1108 if ( (res = CConfig::Instance()->GetPublicHub( hubname, &hubitem )) )
1109 TransferObject->sHubHost = hubitem.m_sHost;
1110 else if ( (res = CConfig::Instance()->GetBookmarkHub( hubname, &hubitem )) )
1111 TransferObject->sHubHost = hubitem.m_sHost;
1112
1113 if ( res == true )
1114 SendFileInfo( TransferObject );
1115 }
1116
1117 m_pDownloadQueue->pQueueMutex->UnLock();
1118
1119 return res;
1120 }
1121
1122 /** */
DLM_QueueGetHub(CString nick,CString hubname,CList<DCHubObject> * list)1123 void CDownloadManager::DLM_QueueGetHub( CString nick, CString hubname, CList<DCHubObject> * list )
1124 {
1125 DCTransferQueueObject * TransferObject;
1126 DCHubObject * HubObject1;
1127
1128 if (!list)
1129 {
1130 return;
1131 }
1132
1133 list->Clear();
1134
1135 m_pDownloadQueue->pQueueMutex->Lock();
1136
1137 if ( (TransferObject = m_pDownloadQueue->GetUserTransferObject( nick, hubname, CString() )) != 0 )
1138 {
1139 HubObject1=0;
1140
1141 while( (HubObject1=TransferObject->pHubList.Next(HubObject1)) != 0 )
1142 list->Add( new DCHubObject(HubObject1) );
1143 }
1144
1145 m_pDownloadQueue->pQueueMutex->UnLock();
1146
1147 return;
1148 }
1149
1150
1151
1152 /** */
DLM_AddTransferRequest(CString nick,CString userhost,CString hubname,CString hubhost)1153 bool CDownloadManager::DLM_AddTransferRequest( CString nick, CString userhost, CString hubname, CString hubhost )
1154 {
1155 bool res;
1156 DCTransferWait * TransferWait;
1157
1158 if ( m_eShutdownState != essNONE )
1159 {
1160 return false;
1161 }
1162
1163 m_pWaitListMutex->Lock();
1164
1165 res = false;
1166 TransferWait = 0;
1167
1168 DPRINTF("ATR: '%s' '%s' '%s' '%s'\n",nick.Data(),userhost.Data(),hubname.Data(),hubhost.Data());
1169
1170 DPRINTF("ATR COUNT: %ld\n",m_pTransferWaitList->Count());
1171
1172 if ( m_pTransferWaitList->Count() < 250 )
1173 {
1174 // check if the user allready in the waitlist
1175 while ( (TransferWait = m_pTransferWaitList->Next(TransferWait)) != 0 )
1176 {
1177 if ( TransferWait->sHubName == hubname )
1178 {
1179 // here one of "nick" or "userhost" will be empty
1180 if ( (TransferWait->sNick == nick) && (TransferWait->sUserHost == userhost) )
1181 {
1182 DPRINTF("ATR FOUND\n");
1183
1184 // reset timeout, ignore it on to fast connections
1185 if ( (time(0)-TransferWait->tTimeout) > 2 )
1186 {
1187 // count in requests from a client
1188 TransferWait->m_nCount++;
1189
1190 TransferWait->tTimeout = time(0);
1191 res = true;
1192 }
1193 else
1194 {
1195 DPRINTF("ATR to fast connections\n");
1196 }
1197
1198 break;
1199 }
1200 }
1201 }
1202
1203 if ( TransferWait == 0 )
1204 {
1205 // user not found, add it
1206 DPRINTF("ATR ADD\n");
1207
1208 TransferWait = new DCTransferWait();
1209 TransferWait->sNick = nick;
1210 TransferWait->sUserHost = userhost;
1211 TransferWait->sHubName = hubname;
1212 TransferWait->sHubHost = hubhost;
1213 TransferWait->tTimeout = time(0);
1214 TransferWait->m_nCount = 1;
1215
1216 m_pTransferWaitList->Add(TransferWait);
1217
1218 res = true;
1219 }
1220 }
1221 else
1222 {
1223 // TODO: warn message ...
1224 }
1225
1226 m_pWaitListMutex->UnLock();
1227
1228 return res;
1229 }
1230
1231 /** */
DLM_AddTransferRequest(CString host,int port,bool crypto,CString hubname,CString hubhost)1232 void CDownloadManager::DLM_AddTransferRequest( CString host, int port, bool crypto, CString hubname, CString hubhost )
1233 {
1234 if ( m_eShutdownState != essNONE )
1235 {
1236 return;
1237 }
1238
1239 DPRINTF("ATR: '%s:%d' %d '%s' '%s'\n",host.Data(),port,crypto,hubname.Data(),hubhost.Data());
1240
1241 // check private address space
1242 if ( !((CConfig::Instance()->GetCheckPrivateAddressSpace() &&
1243 CNetAddr::IsPrivateI4(host.Data())) ||
1244 (CConfig::Instance()->GetPrivateAddressSpaceOnly() &&
1245 (CNetAddr::IsPrivateI4(host.Data()) == false)) ) )
1246 {
1247 // TODO: check if client allready in the transfer wait list
1248 // create a new transfer
1249 CTransferObject * TransferObject = new CTransferObject();
1250 TransferObject->m_pTransfer = new CTransfer();
1251
1252 TransferObject->m_pTransfer->SetTransferID( GetNewID() );
1253 TransferObject->m_pTransfer->SetNick( CConfig::Instance()->GetNick( hubname, hubhost ) );
1254
1255 TransferObject->m_pTransfer->SetHubName(hubname);
1256 TransferObject->m_pTransfer->SetHubHost(hubhost);
1257
1258 TransferObject->m_pTransfer->SetHost( host, port );
1259 TransferObject->m_pTransfer->SetRate( CConfig::Instance()->GetMaxUploadRate() );
1260
1261 if ( crypto )
1262 {
1263 if ( TransferObject->m_pTransfer->ChangeSocketMode( esmFULLSSLCLIENT, CConfig::Instance()->GetTransferCert(), CConfig::Instance()->GetTransferKey() ) == false )
1264 {
1265 DPRINTF("New transfer change to SSL client mode failed\n");
1266 delete TransferObject;
1267 return;
1268 }
1269 }
1270
1271 // add this transfer to the wait list
1272 if ( DLM_AddTransferRequest( CString(), TransferObject->m_pTransfer->GetHost(), hubname, hubhost ) == false )
1273 {
1274 // request allready in the list
1275 delete TransferObject;
1276 }
1277 else
1278 {
1279 m_pTransfersMutex->Lock();
1280
1281 m_pTransferList->Add( CString::number(TransferObject->m_pTransfer->GetTransferID()), TransferObject );
1282 TransferObject->m_pTransfer->SetCallBackFunction( new CCallback2<CDownloadManager, CTransfer, CDCMessage*>( this, &CDownloadManager::DM_TransferCallBack ) );
1283
1284 DPRINTF("ATR CONNECT: %s:%d %d %s %s\n",host.Data(),port,crypto,hubname.Data(),hubhost.Data());
1285
1286 // connect to the client
1287 TransferObject->m_pTransfer->Connect();
1288
1289 m_pTransfersMutex->UnLock();
1290 }
1291 }
1292 else
1293 {
1294 // send warning
1295 CString logmsg = "Ignoring connection to: ";
1296 logmsg += host;
1297 logmsg += ':';
1298 logmsg += CString::number(port);
1299 logmsg += " at hub '";
1300 logmsg += hubname;
1301 logmsg += "' (";
1302 logmsg += hubhost;
1303 logmsg += ") due to private address space settings";
1304 SendLogInfo( logmsg );
1305 }
1306 }
1307
1308 /** */
DLM_GetDownloadManagerInfo(CDownloadManagerInfo * pinfo)1309 bool CDownloadManager::DLM_GetDownloadManagerInfo( CDownloadManagerInfo * pinfo )
1310 {
1311 *pinfo = DownloadManagerInfo;
1312
1313 return true;
1314 }
1315
1316 /** handle search */
DLM_HandleSearch(CMessageSearchResult * MessageSearchResult)1317 bool CDownloadManager::DLM_HandleSearch( CMessageSearchResult * MessageSearchResult )
1318 {
1319 bool res = false;
1320 CMessageSearchResult * msg = 0;
1321 DCTransferFileObject * tfo1=0, * tfo2=0;
1322
1323 while ( (msg = m_pSearchList->Next(msg)) != 0 )
1324 {
1325 //MessageSearchResult->sNick += "+";
1326 if ( msg->m_sHash == MessageSearchResult->m_sHash )
1327 {
1328 // handle this file
1329 m_pDownloadQueue->pQueueMutex->Lock();
1330
1331 // check if this file allready in the queue
1332 if ( m_pDownloadQueue->GetUserFileObject( MessageSearchResult->m_sNick, MessageSearchResult->m_sHubName, MessageSearchResult->m_sHubHost, MessageSearchResult->m_sFile ) == 0 )
1333 {
1334 // get original file
1335 if ( (tfo1=m_pDownloadQueue->GetUserFileObject( msg->m_sNick, msg->m_sHubName, msg->m_sHubHost, msg->m_sFile )) != 0 )
1336 {
1337 tfo2 = new DCTransferFileObject(*tfo1);
1338 }
1339 }
1340
1341 m_pDownloadQueue->pQueueMutex->UnLock();
1342
1343 if ( tfo2 )
1344 break;
1345 }
1346 }
1347
1348 if ( tfo2 )
1349 {
1350 CDir dir;
1351 CString path,file;
1352 int adj = 0;
1353
1354 dir.SplitPathFile( tfo2->m_sLocalFile, path, file );
1355
1356 // remove tfo2->m_sLocalPath from path
1357 if ( (path.Right(1) == DIRSEPARATOR) && (tfo2->m_sLocalPath.Right(1) != DIRSEPARATOR) )
1358 {
1359 adj = 1;
1360 }
1361 else if ( (path.Right(1) != DIRSEPARATOR) && (tfo2->m_sLocalPath.Right(1) == DIRSEPARATOR) )
1362 {
1363 adj = -1;
1364 }
1365
1366 path = path.Left( path.Length() - (tfo2->m_sLocalPath.Length() + adj) );
1367
1368 DLM_QueueAdd( MessageSearchResult->m_sNick,
1369 MessageSearchResult->m_sHubName,
1370 MessageSearchResult->m_sHubHost,
1371 MessageSearchResult->m_sFile,
1372 tfo2->m_sLocalFileName,
1373 tfo2->m_sLocalPath,
1374 path,
1375 tfo2->m_eMedium,
1376 tfo2->m_nSize,
1377 0, 0,
1378 MessageSearchResult->m_sHash,
1379 true );
1380 delete tfo2;
1381 }
1382
1383 return res;
1384 }
1385
1386 /** */
SendFileInfo(DCTransferQueueObject * TransferObject,DCTransferFileObject * TransferFileObject,bool bRemoveFile)1387 void CDownloadManager::SendFileInfo( DCTransferQueueObject * TransferObject, DCTransferFileObject * TransferFileObject, bool bRemoveFile )
1388 {
1389 if ( m_eShutdownState != essNONE )
1390 return;
1391
1392 LogMutex.Lock();
1393
1394 CMessageDMFileObject * fo = new CMessageDMFileObject();
1395
1396 fo->m_sNick = TransferObject->sNick;
1397 fo->m_sHubName = TransferObject->sHubName;
1398 fo->m_sHubHost = TransferObject->sHubHost;
1399 fo->m_eTransferWaitState = TransferObject->eState;
1400 fo->m_tTimeout = TransferObject->tTimeout;
1401 fo->m_bRemoveFile = bRemoveFile;
1402 fo->m_nConnections = TransferObject->iConnections;
1403
1404 if ( TransferFileObject )
1405 {
1406 fo->m_sRemoteFile = TransferFileObject->m_sRemoteFile;
1407 fo->m_sLocalFile = TransferFileObject->m_sLocalFile;
1408 fo->m_nSize = TransferFileObject->m_nSize;
1409 fo->m_eTransferFileState = TransferFileObject->m_eState;
1410 fo->m_bMulti = TransferFileObject->m_bMulti;
1411 fo->m_nPriority = TransferFileObject->m_nPriority;
1412 fo->m_sTTH = TransferFileObject->m_sHash;
1413
1414 if ( TransferFileObject->m_pDirList )
1415 {
1416 fo->m_pDirList = new std::list<CString>();
1417 *(fo->m_pDirList) = *(TransferFileObject->m_pDirList);
1418 }
1419 }
1420
1421 if ( DC_DownloadManagerCallBack(fo) == -1 )
1422 delete fo;
1423
1424 LogMutex.UnLock();
1425 }
1426
1427 /** */
CreateDMTransferObject(CTransfer * Transfer)1428 CMessageDMTransferObject * CDownloadManager::CreateDMTransferObject( CTransfer * Transfer )
1429 {
1430 DCFileChunkObject * FileChunkObject;
1431 CMessageDMTransferObject * to = new CMessageDMTransferObject();
1432
1433 to->m_nTransferID = Transfer->GetTransferID();
1434 to->m_sSrcNick = Transfer->GetNick();
1435 to->m_sDstNick = Transfer->GetDstNick();
1436 to->sHost = Transfer->GetHost();
1437 to->m_sHubHost = Transfer->GetHubHost();
1438 to->sHubName = Transfer->GetHubName();
1439 to->eState = Transfer->GetMode();
1440 to->m_sDstFile = Transfer->GetDstFilename();
1441 to->m_sSrcFile = Transfer->GetSrcFilename();
1442 to->lSize = Transfer->GetLength();
1443 to->lStartPosition = Transfer->GetStartPosition();
1444 to->lEndPosition = Transfer->GetEndPosition();
1445 to->lRate = Transfer->GetTransferrate();
1446 to->lTransfered = Transfer->GetTransfered();
1447 to->m_bEncrypted = Transfer->GetEncrypted();
1448 to->m_sTTH = Transfer->GetTTH();
1449
1450 // get size done from the chunk list
1451 if ( Transfer->GetSrcDirection() == edUPLOAD )
1452 {
1453 to->lSizeDone = to->lStartPosition + to->lTransfered;
1454 }
1455 else
1456 {
1457 m_pDownloadQueue->pChunksMutex->Lock();
1458
1459 if ( Transfer->GetMedium() == eltBUFFER )
1460 {
1461 to->lSizeDone = to->lStartPosition + to->lTransfered;
1462 }
1463 else if ( (FileChunkObject = m_pDownloadQueue->GetFileChunkObject(Transfer->GetSrcFilename())) != 0 )
1464 {
1465 to->lSizeDone = FileChunkObject->m_nSizeDone+to->lTransfered;
1466 }
1467 else
1468 {
1469 to->lSizeDone = to->lSize;
1470 }
1471
1472 m_pDownloadQueue->pChunksMutex->UnLock();
1473 }
1474
1475 return to;
1476 }
1477
1478 /** */
DLM_TransferGetList()1479 CList<CMessageDMTransferObject> * CDownloadManager::DLM_TransferGetList()
1480 {
1481 CTransferObject * TransferObject = 0;
1482 CList<CMessageDMTransferObject> * list;
1483 CMessageDMTransferObject * to;
1484
1485 m_pTransfersMutex->Lock();
1486
1487 list = new CList<CMessageDMTransferObject>();
1488
1489 while( m_pTransferList->Next( &TransferObject ) )
1490 {
1491 to = CreateDMTransferObject(TransferObject->m_pTransfer);
1492 list->Add(to);
1493 }
1494
1495 m_pTransfersMutex->UnLock();
1496
1497 return list;
1498 }
1499
1500 /** */
SendTransferInfo(CTransfer * Transfer,bool remove)1501 void CDownloadManager::SendTransferInfo( CTransfer * Transfer, bool remove )
1502 {
1503 LogMutex.Lock();
1504
1505 CMessageDMTransferObject * to = CreateDMTransferObject(Transfer);
1506
1507 to->bRemoveTransfer = remove;
1508
1509 if ( DC_DownloadManagerCallBack(to) == -1 )
1510 delete to;
1511
1512 LogMutex.UnLock();
1513 }
1514
1515 /** */
SendSlotInfo(CExtraUserSlot * Object)1516 void CDownloadManager::SendSlotInfo( CExtraUserSlot * Object )
1517 {
1518 LogMutex.Lock();
1519
1520 CMessageDMSlotObject * so = new CMessageDMSlotObject();
1521
1522 so->sNick = Object->sNick;
1523 so->sHubName = Object->sHubName;
1524 so->iSlots = Object->iSlots;
1525 so->bPermanent = Object->bPermanent;
1526
1527 if ( DC_DownloadManagerCallBack(so) == -1 )
1528 delete so;
1529
1530 LogMutex.UnLock();
1531 }
1532
1533 /** */
SendLogInfo(CString message,CTransfer * Transfer)1534 void CDownloadManager::SendLogInfo( CString message, CTransfer * Transfer )
1535 {
1536 LogMutex.Lock();
1537
1538 CMessageLog * log = new CMessageLog();
1539
1540 if ( Transfer != 0 )
1541 {
1542 log->sMessage = "[";
1543 if ( Transfer->GetDstNick().IsEmpty() )
1544 log->sMessage += "???";
1545 else
1546 log->sMessage += Transfer->GetDstNick();
1547 log->sMessage += "] ";
1548 }
1549
1550 log->sMessage += message;
1551
1552 // write message in log tab in transfer window to logfile
1553 if ( CConfig::Instance()->GetLogFile() && CConfig::Instance()->GetLogDetails() )
1554 {
1555 CLogFile::Write(CConfig::Instance()->GetLogFileName(),eltINFO,log->sMessage);
1556 }
1557
1558 if ( DC_DownloadManagerCallBack(log) == -1 )
1559 delete log;
1560
1561 LogMutex.UnLock();
1562 }
1563
1564 /** */
SendDownloadManagerInfo(CDownloadManagerInfo * dminfo)1565 void CDownloadManager::SendDownloadManagerInfo( CDownloadManagerInfo * dminfo )
1566 {
1567 if ( !dminfo )
1568 {
1569 return;
1570 }
1571
1572 LogMutex.Lock();
1573
1574 CDownloadManagerInfo * dmi = new CDownloadManagerInfo;
1575
1576 *dmi = *dminfo;
1577
1578 if ( DC_DownloadManagerCallBack(dmi) == -1 )
1579 delete dmi;
1580
1581 LogMutex.UnLock();
1582 }
1583
1584 /** */
SendTrafficInfo()1585 void CDownloadManager::SendTrafficInfo()
1586 {
1587 LogMutex.Lock();
1588
1589 DCMessageTraffic * to = new DCMessageTraffic();
1590
1591 to->m_nRx = CSocket::m_Traffic.GetTraffic(ettRX);
1592 to->m_nTx = CSocket::m_Traffic.GetTraffic(ettTX);
1593 to->m_nDataRx = CSocket::m_Traffic.GetTraffic(ettDATARX);
1594 to->m_nDataTx = CSocket::m_Traffic.GetTraffic(ettDATATX);
1595 to->m_nControlRx = CSocket::m_Traffic.GetTraffic(ettCONTROLRX);
1596 to->m_nControlTx = CSocket::m_Traffic.GetTraffic(ettCONTROLTX);
1597
1598 if ( DC_DownloadManagerCallBack(to) == -1 )
1599 delete to;
1600
1601 LogMutex.UnLock();
1602 }
1603
1604 /** */
SendFileManagerInfo(CFileManagerInfo * info)1605 void CDownloadManager::SendFileManagerInfo( CFileManagerInfo * info )
1606 {
1607 if ( m_eShutdownState != essNONE )
1608 {
1609 return;
1610 }
1611
1612 if ( !info )
1613 {
1614 return;
1615 }
1616
1617 LogMutex.Lock();
1618
1619 CFileManagerInfo * fmi = new CFileManagerInfo();
1620
1621 *fmi = *info;
1622
1623 if ( DC_DownloadManagerCallBack(fmi) == -1 )
1624 delete fmi;
1625
1626 LogMutex.UnLock();
1627 }
1628
1629 /** */
CheckUserSlot(CString nick,CString hubname)1630 bool CDownloadManager::CheckUserSlot( CString nick, CString hubname )
1631 {
1632 bool res;
1633 CExtraUserSlot * ExtraUserSlot;
1634
1635 m_pExtraSlotsMutex->Lock();
1636
1637 res = false;
1638 ExtraUserSlot = 0;
1639
1640 while( (ExtraUserSlot=m_pExtraUserSlotList->Next(ExtraUserSlot)) != 0 )
1641 {
1642 if ( (ExtraUserSlot->sNick == nick) && (ExtraUserSlot->sHubName == hubname) )
1643 {
1644 if ( ExtraUserSlot->bPermanent )
1645 {
1646 res = true;
1647 }
1648 else if ( ExtraUserSlot->iSlots > 0 )
1649 {
1650 ExtraUserSlot->iSlots--;
1651
1652 SendSlotInfo(ExtraUserSlot);
1653
1654 if ( ExtraUserSlot->iSlots == 0 )
1655 {
1656 m_pExtraUserSlotList->Del(ExtraUserSlot);
1657 }
1658
1659 res = true;
1660 }
1661 else
1662 {
1663 printf("Warning extra user slot for '%s' on '%s' with slots %d deleted!\n",ExtraUserSlot->sNick.Data(),ExtraUserSlot->sHubName.Data(),ExtraUserSlot->iSlots);
1664 m_pExtraUserSlotList->Del(ExtraUserSlot);
1665 }
1666
1667 break;
1668 }
1669 }
1670
1671 m_pExtraSlotsMutex->UnLock();
1672
1673 return res;
1674 }
1675
1676 /** */
FileListDone(CTransfer * Transfer,DCTransferFileObject * TransferFileObject)1677 void CDownloadManager::FileListDone( CTransfer * Transfer, DCTransferFileObject * TransferFileObject )
1678 {
1679 DCTransferQueueObject * TransferObject;
1680 CString fn;
1681
1682 // CTransfer has been modified to:
1683 // set the correct src name DC_USER_FILELIST_XMLBZ or DC_USER_FILELIST_BZ or DC_USER_FILELIST_HE3
1684 // and not bz2/he3 decompress the buffer
1685 // and provide a function to save it's buffer to a file
1686 if ( (TransferObject = m_pDownloadQueue->GetUserTransferObject( Transfer->GetDstNick(), Transfer->GetHubName(), Transfer->GetHubHost() )) != 0 )
1687 {
1688 fn = Transfer->GetDstNick();
1689 fn += '@';
1690 fn += Transfer->GetHubHost();
1691
1692 // convert invalid characters - from dcchat.cpp line 1156
1693 fn.Swap( '/', '_' );
1694 fn.Swap( '\\', '_' );
1695 fn.Swap( ':', '_' );
1696
1697 if ( Transfer->GetSrcFilename() == DC_USER_FILELIST_XMLBZ )
1698 {
1699 fn += ".xml.bz2";
1700 }
1701 else if ( Transfer->GetSrcFilename() == DC_USER_FILELIST_BZ )
1702 {
1703 fn += ".bz2";
1704 }
1705 else if ( Transfer->GetSrcFilename() == DC_USER_FILELIST_HE3 )
1706 {
1707 fn += ".DcLst";
1708 }
1709 else
1710 {
1711 printf("CDownloadManager::FileListDone: unknown filelist type '%s'\n", Transfer->GetSrcFilename().Data());
1712 fn += ".filelist";
1713 }
1714
1715 fn = CConfig::Instance()->GetFileListPath() + fn;
1716
1717 if ( Transfer->SaveBufferToFile(fn) )
1718 {
1719 CMessageDMFileListObject * flo = new CMessageDMFileListObject();
1720
1721 flo->sNick = TransferObject->sNick;
1722 flo->sHubName = TransferObject->sHubName;
1723 flo->sHubHost = TransferObject->sHubHost;
1724 flo->sLocalFile = fn;
1725
1726 flo->sJumpTo = TransferFileObject->m_sJumpTo;
1727
1728 if ( TransferFileObject->m_pDirList )
1729 {
1730 flo->m_pDirList = new std::list<CString>();
1731 *(flo->m_pDirList) = *(TransferFileObject->m_pDirList);
1732 }
1733
1734 LogMutex.Lock();
1735
1736 if ( DC_DownloadManagerCallBack(flo) == -1 )
1737 delete flo;
1738
1739 LogMutex.UnLock();
1740 }
1741 else
1742 {
1743 TransferFileObject->m_eState = etfsERROR;
1744 SendFileInfo( TransferObject, TransferFileObject );
1745 SendLogInfo( "Error saving filelist " + fn, Transfer );
1746 }
1747 }
1748 }
1749
1750 /** */
CheckHash(CTransfer * Transfer)1751 bool CDownloadManager::CheckHash( CTransfer * Transfer )
1752 {
1753 bool res = false;
1754 CByteArray ba;
1755 DCTransferFileObject * TransferFileObject;
1756 DCFileChunkObject * FileChunkObject;
1757 md5_ctx * context = 0;
1758 unsigned char resbuf[16];
1759 char c[3];
1760 int i = 0;
1761 CString result;
1762
1763 if ( (TransferFileObject = m_pDownloadQueue->GetUserFileObject( Transfer->GetDstNick(), Transfer->GetHubName(), Transfer->GetHubHost(), Transfer->GetDstFilename() )) != 0 )
1764 {
1765 if ( Transfer->GetBuffer(&ba) != 0 )
1766 {
1767 if ( (TransferFileObject->m_stHash.IsEmpty()) && TransferFileObject->m_bMulti )
1768 {
1769 // calc hash
1770 context = new md5_ctx();
1771
1772 md5_init_ctx( context );
1773 md5_process_bytes( ba.Data(), ba.Size(), context );
1774 md5_finish_ctx( context, &resbuf );
1775
1776 delete context;
1777
1778 // convert digest to hexadecimal
1779 for ( i = 0; i < 16; i++ )
1780 {
1781 #ifdef WIN32
1782 _snprintf( c, 3, "%02x", resbuf[i] );
1783 #else
1784 snprintf( c, 3, "%02x", resbuf[i] );
1785 #endif
1786 result += c;
1787 }
1788
1789 TransferFileObject->m_stHash = result;
1790
1791 DPRINTF("hash is :'%s'\n",TransferFileObject->m_stHash.Data());
1792
1793 m_pDownloadQueue->pChunksMutex->Lock();
1794
1795 if ( m_pDownloadQueue->pChunkList->Get( Transfer->GetSrcFilename(), &FileChunkObject ) == 0 )
1796 {
1797 if ( FileChunkObject->m_stHash.IsEmpty() )
1798 {
1799 DPRINTF("Set hash ...\n");
1800 FileChunkObject->m_stHash = TransferFileObject->m_stHash;
1801
1802 res = true;
1803 }
1804 else if ( FileChunkObject->m_stHash == TransferFileObject->m_stHash )
1805 {
1806 DPRINTF("Hash ok...\n");
1807
1808 res = true;
1809 }
1810 else
1811 {
1812 DPRINTF("Wrong hash !!!\n");
1813 TransferFileObject->m_eState = etfsERROR;
1814 }
1815 }
1816 else
1817 {
1818 DPRINTF("warning file chunk object not found\n");
1819 }
1820
1821 m_pDownloadQueue->pChunksMutex->UnLock();
1822 }
1823 else
1824 {
1825 DPRINTF("warning hash not empty or no multi download\n");
1826 }
1827 }
1828 else
1829 {
1830 DPRINTF("warning file object not found\n");
1831 }
1832 }
1833 else
1834 {
1835 DPRINTF("warning get buffer error\n");
1836 }
1837
1838 return res;
1839 }
1840
1841 /**
1842 bool CDownloadManager::SetMultiDownload( CString nick, CString hubname, CString remotefile )
1843 {
1844 Lock();
1845 bool res = false;
1846 DCTransferQueueObject * TransferObject;
1847 DCTransferFileObject * TransferFileObject;
1848 DCFileChunkObject * FileChunkObject;
1849
1850 if ( (TransferObject = m_pDownloadQueue->GetUserTransferObject( nick, hubname )) != 0 )
1851 {
1852 UserFileInfo->eWaitState = TransferObject->eState;
1853 UserFileInfo->sUserFileList = TransferObject->sUserFileList;
1854
1855 if ( TransferObject->pTransferFileList.Get( remotefile, &TransferFileObject ) == 0 )
1856 {
1857 if ( (TransferFileObject->eTransferFileState != etfsTRANSFER) &&
1858 (TransferFileObject->bMulti == false) )
1859 {
1860 m_pDownloadQueue->pChunksMutex->Lock();
1861
1862 if ( (FileChunkObject = m_pDownloadQueue->GetFileChunkObject(TransferFileObject->sLocalFile)) != 0 )
1863 {
1864 DCChunkObject * ChunkObject = 0;
1865 while( (ChunkObject=FileChunkObject->pChunks.Next(ChunkObject)) != 0 )
1866 {
1867 if ( ChunkObject->lStart <= TEST_CHUNK_SIZE )
1868 {
1869 // error
1870 break;
1871 }
1872 }
1873
1874 if ( ChunkObject == 0 )
1875 }
1876
1877 m_pDownloadQueue->pChunksMutex->UnLock();
1878 }
1879
1880 UserFileInfo->eFileState = TransferFileObject->eState;
1881 UserFileInfo->sLocalFile = TransferFileObject->sLocalFile;
1882 UserFileInfo->bMulti = TransferFileObject->bMulti;
1883 res = true;
1884 }
1885 }
1886
1887 UnLock();
1888
1889 return res;
1890 }
1891 */
1892
1893 /** */
GetNewID()1894 ulonglong CDownloadManager::GetNewID()
1895 {
1896 return ((++m_nID)==0) ? (++m_nID) : (m_nID);
1897 }
1898
1899 /** */
RemoveQueueFile(CString localfile)1900 bool CDownloadManager::RemoveQueueFile( CString localfile )
1901 {
1902 bool res = false;
1903 CStringList<DCTransferQueueObject> * StringList = 0;
1904 DCTransferQueueObject * TransferObject;
1905 DCTransferFileObject * TransferFileObject;
1906
1907 // remove file from the chunk list
1908 m_pDownloadQueue->pChunksMutex->Lock();
1909 m_pDownloadQueue->pChunkList->Del( localfile );
1910 m_pDownloadQueue->pChunksMutex->UnLock();
1911
1912 // remove file from the queue
1913
1914 while( m_pDownloadQueue->pQueue->Next( &StringList ) )
1915 {
1916 TransferObject = 0;
1917
1918 while( StringList->Next( &TransferObject) )
1919 {
1920 TransferFileObject = 0;
1921
1922 while( TransferObject->pTransferFileList.Next( &TransferFileObject) )
1923 {
1924 if ( TransferFileObject->m_sLocalFile == localfile )
1925 {
1926 // on file transfer don't remove the file
1927 if ( TransferFileObject->m_eState != etfsTRANSFER )
1928 {
1929 SendFileInfo( TransferObject, TransferFileObject, true );
1930 TransferObject->pTransferFileList.Del(TransferFileObject->m_sRemoteFile);
1931 TransferFileObject = 0;
1932 res = true;
1933 }
1934 else
1935 {
1936 DPRINTF("WARNING: RemoveQueueFile: file transfer is running\n");
1937 }
1938 }
1939 }
1940 }
1941 }
1942
1943 return res;
1944 }
1945
1946 /** */
RemoveQueueFile(CString nick,CString hubname,CString remotefile)1947 bool CDownloadManager::RemoveQueueFile( CString nick, CString hubname, CString remotefile )
1948 {
1949 bool res = false;
1950 DCTransferFileObject * TransferFileObject = 0;
1951 DCTransferQueueObject * TransferObject = 0;
1952
1953 if ( (TransferObject = m_pDownloadQueue->GetUserTransferObject( nick, hubname, CString() )) != 0 )
1954 {
1955 if ( remotefile.NotEmpty() )
1956 {
1957 if ( (TransferFileObject = m_pDownloadQueue->GetUserFileObject( nick, hubname, CString(), remotefile )) != 0 )
1958 {
1959 if ( TransferFileObject->m_eState != etfsTRANSFER )
1960 {
1961 res = true;
1962 }
1963 else
1964 {
1965 DPRINTF("WARNING: RemoveQueueFile: file transfer is running\n");
1966 }
1967 }
1968 }
1969 else
1970 {
1971 if ( TransferObject->eState != etwsRUN )
1972 {
1973 res = true;
1974 }
1975 else
1976 {
1977 DPRINTF("WARNING: RemoveQueueFile: transfer is running\n");
1978 }
1979 }
1980
1981 if ( res )
1982 {
1983 SendFileInfo( TransferObject, TransferFileObject, true );
1984 res = m_pDownloadQueue->DelUserFileObject( nick, hubname, CString(), remotefile );
1985 }
1986 }
1987
1988 return res;
1989 }
1990
1991 /** */
UpdateWaitTransfer(CTransfer * Transfer,bool rem)1992 bool CDownloadManager::UpdateWaitTransfer( CTransfer * Transfer, bool rem )
1993 {
1994 bool res = false;
1995 DCTransferWait * TransferWait = 0;
1996 CString thost;
1997
1998 // search in the wait list ...
1999 m_pWaitListMutex->Lock();
2000
2001 /*
2002 * For an incoming connection the port it came from is random, so will
2003 * be different for each attempt, so do not put it in into the list.
2004 */
2005 if ( Transfer->IsListener() )
2006 {
2007 thost = Transfer->GetIP();
2008 }
2009 else
2010 {
2011 thost = Transfer->GetHost();
2012 }
2013
2014 DPRINTF("UWT: Search user %s %s in the waitlist\n",Transfer->GetDstNick().Data(),thost.Data());
2015
2016 while ( (TransferWait = m_pTransferWaitList->Next(TransferWait)) != 0 )
2017 {
2018 // here we have both nick and host from the CTransfer
2019 // search for the nick+host or one of them and fill in the other
2020 if ( TransferWait->Match( Transfer->GetDstNick(), thost ) )
2021 {
2022 Transfer->SetHubName(TransferWait->sHubName);
2023 Transfer->SetHubHost(TransferWait->sHubHost);
2024
2025 DPRINTF("UWT: User found\n");
2026
2027 res = true;
2028 break;
2029 }
2030 }
2031
2032 if ( !TransferWait )
2033 {
2034 DPRINTF("UWT: User not found\n");
2035 }
2036 else
2037 {
2038 if ( rem )
2039 {
2040 TransferWait->m_nCount--;
2041
2042 DPRINTF("UWT: Remove user %lld\n",TransferWait->m_nCount);
2043
2044 if ( TransferWait->m_nCount == 0 )
2045 m_pTransferWaitList->Del(TransferWait);
2046 }
2047 }
2048
2049 m_pWaitListMutex->UnLock();
2050
2051 return res;
2052 }
2053
2054 /** */
CheckWaitTransfer(CTransfer * Transfer)2055 eDirection CDownloadManager::CheckWaitTransfer( CTransfer * Transfer )
2056 {
2057 m_pDownloadQueue->pQueueMutex->Lock();
2058
2059 eDirection res = edNONE;
2060 DCTransferQueueObject * TransferObject;
2061 DCTransferBanObject * TransferBanObject = 0;
2062 CString host;
2063 bool waittransfer;
2064 int port;
2065 bool ban = false;
2066 long int i;
2067
2068 DPRINTF("CWT: '%s' on '%s'\n",
2069 Transfer->GetDstNick().Data(),
2070 Transfer->GetHubName().Data() );
2071
2072 // allow only 1 request in 30 seconds
2073 m_pBanListMutex->Lock();
2074
2075 if ( Transfer->GetPeerName( &host, &port ) == false )
2076 {
2077 // error
2078 DPRINTF("CWT: Error: Can't get peername\n");
2079 }
2080 else if ( m_pTransferBanList->Get( Transfer->GetDstNick(), &TransferBanObject ) != 0 )
2081 {
2082 DPRINTF("CWT: Create new TransferBanObject '%s'\n",host.Data());
2083
2084 TransferBanObject = new DCTransferBanObject();
2085
2086 TransferBanObject->m_sIP = host;
2087 TransferBanObject->m_tTime = time(0);
2088
2089 m_pTransferBanList->Add( Transfer->GetDstNick(), TransferBanObject );
2090
2091 DPRINTF("CWT: Banlist count %ld objects\n",m_pTransferBanList->Count());
2092 }
2093
2094 if ( TransferBanObject && (TransferBanObject->m_nRequestCount > 0) )
2095 {
2096 i = lrint(ceil((time(0)-TransferBanObject->m_tTime)/60.0)*4);
2097
2098 if ( i < TransferBanObject->m_nRequestCount )
2099 {
2100 ban = true;
2101 }
2102 }
2103
2104 waittransfer = UpdateWaitTransfer( Transfer );
2105
2106 DPRINTF("CWT: CheckWaitTransfer II: %s on %s\n",
2107 Transfer->GetDstNick().Data(),
2108 Transfer->GetHubName().Data() );
2109
2110 // now we check if we need to set the correct nick for the hub
2111 if ( Transfer->GetNick().IsEmpty() )
2112 {
2113 Transfer->SetNick( CConfig::Instance()->GetNick( Transfer->GetHubName(), Transfer->GetHubHost() ) );
2114
2115 DPRINTF("CWT: Set transfer NICK: '%s'\n",Transfer->GetNick().Data() );
2116
2117 // send the correct nick
2118 Transfer->SendMyNick( Transfer->GetNick(), Transfer->GetHubHost() );
2119 }
2120
2121 if ( (TransferObject = m_pDownloadQueue->GetUserTransferObject( Transfer->GetDstNick(), Transfer->GetHubName(), Transfer->GetHubHost() )) != 0 )
2122 {
2123 DPRINTF("CWT: Waiting: %s on %s %s\n",
2124 TransferObject->sNick.Data(),
2125 TransferObject->sHubName.Data(),
2126 TransferObject->sHubHost.Data() );
2127
2128 if ( TransferObject->eState == etwsIDLE )
2129 {
2130 SendLogInfo( "WARNING: Increase the response timeout." );
2131 }
2132
2133 if ( (TransferObject->eState == etwsWAIT) || (TransferObject->eState == etwsIDLE) )
2134 {
2135 DPRINTF("CWT: wait found ...\n");
2136
2137 TransferObject->eState = etwsRUN;
2138 TransferObject->iConnections++;
2139
2140 // waiting transfer found ...
2141 res = edDOWNLOAD;
2142
2143 SendFileInfo( TransferObject );
2144 }
2145 else
2146 {
2147 DPRINTF("CWT: ERROR: wait in wrong state (please report!) (%d/%d)\n",TransferObject->eState,TransferObject->iConnections);
2148 }
2149 }
2150
2151 if ( res == edNONE )
2152 {
2153 if ( waittransfer )
2154 {
2155 if ( TransferBanObject )
2156 {
2157 TransferBanObject->m_nRequestCount++;
2158 DPRINTF("CWT: Requestcount is now %d\n",TransferBanObject->m_nRequestCount);
2159 }
2160
2161 if ( ban )
2162 {
2163 Transfer->Disconnect(true);
2164 SendLogInfo( "WARNING: Disconnect aggressive client " + host );
2165
2166 DPRINTF("CWT: Host banned\n");
2167 }
2168 else
2169 {
2170 res = edUPLOAD;
2171 }
2172 }
2173 else
2174 {
2175 DPRINTF("CWT: Warning: no wait transfer found for '%s'\n",Transfer->GetDstNick().Data());
2176 Transfer->Disconnect(true);
2177 }
2178 }
2179
2180 m_pBanListMutex->UnLock();
2181
2182 m_pDownloadQueue->pQueueMutex->UnLock();
2183
2184 return res;
2185 }
2186
2187 /** */
ChangeDirection(CTransfer * Transfer)2188 bool CDownloadManager::ChangeDirection( CTransfer * Transfer )
2189 {
2190 bool res = false;
2191 DCTransferQueueObject * TransferObject;
2192
2193 m_pDownloadQueue->pQueueMutex->Lock();
2194
2195 if ( (TransferObject = m_pDownloadQueue->GetUserTransferObject( Transfer->GetDstNick(), Transfer->GetHubName(), Transfer->GetHubHost() )) != 0 )
2196 {
2197 DPRINTF("Waiting: %s on %s %s\n",
2198 TransferObject->sNick.Data(),
2199 TransferObject->sHubName.Data(),
2200 TransferObject->sHubHost.Data() );
2201
2202 // change to upload ...
2203 if ( Transfer->GetSrcDirection() == edDOWNLOAD )
2204 {
2205 if ( TransferObject->eState == etwsRUN )
2206 {
2207 if ( TransferObject->iConnections > 0 )
2208 TransferObject->iConnections--;
2209 else
2210 DPRINTF("WARNING: ChangeDirection: RUN:0\n");
2211 if ( TransferObject->iConnections == 0 )
2212 TransferObject->eState = etwsIDLE;
2213 SendFileInfo( TransferObject );
2214
2215 DPRINTF("change transfer -> upload ...\n");
2216
2217 res = true;
2218 }
2219 else
2220 {
2221 DPRINTF("can't change transfer upload ...\n");
2222 }
2223 }
2224 }
2225
2226 m_pDownloadQueue->pQueueMutex->UnLock();
2227
2228 return res;
2229 }
2230
2231 /** */
SetNextFile(CTransfer * Transfer)2232 bool CDownloadManager::SetNextFile( CTransfer * Transfer )
2233 {
2234 bool res;
2235
2236 m_pDownloadQueue->pQueueMutex->Lock();
2237 res = SetFile(Transfer);
2238 m_pDownloadQueue->pQueueMutex->UnLock();
2239
2240 return res;
2241 }
2242
2243 /** */
SetDirection(CTransfer * Transfer)2244 bool CDownloadManager::SetDirection( CTransfer * Transfer )
2245 {
2246 CTransferObject * TransferObject;
2247 int i;
2248 bool res = false;
2249
2250 // check if transfer mode correct
2251 if ( (Transfer->GetSrcDirection() == edNONE) ||
2252 (Transfer->GetDstDirection() == edNONE) )
2253 {
2254 // never use slots for wrong transfer modes
2255 return res;
2256 }
2257
2258 // check max uploads for a user
2259 if ( Transfer->GetSrcDirection() == edUPLOAD )
2260 {
2261 // check for max user upload slots
2262 TransferObject = 0;
2263 i = 0;
2264
2265 // the list is allready locked by the thread
2266 while( m_pTransferList->Next( &TransferObject ) )
2267 {
2268 if ( TransferObject->m_pTransfer->GetDstDirection() == edDOWNLOAD )
2269 {
2270 if ( Transfer->GetDstNick() == TransferObject->m_pTransfer->GetDstNick() )
2271 {
2272 i++;
2273 }
2274 }
2275 }
2276
2277 // the current transfer is allready in the list
2278 if ( (CConfig::Instance()->GetUserUploadSlots() == 0) ||
2279 (CConfig::Instance()->GetUserUploadSlots() >= i) )
2280 {
2281 // check slot limit
2282 i = CConfig::Instance()->GetMaxUpload();
2283
2284 // unlimited slots == 0 or not all slots used
2285 if ( (i == 0) || (i > DownloadManagerInfo.slot_use_settings) )
2286 {
2287 DownloadManagerInfo.slot_use_settings++;
2288 Transfer->SetTransferType(ettSETTINGS);
2289 res = true;
2290 }
2291 else if ( (CConfig::Instance()->GetExtraSlotsRate() > 0) &&
2292 (DownloadManagerInfo.slot_use_rate_extra < CConfig::Instance()->GetMaxExtraSlots()) &&
2293 (DownloadManagerInfo.Rate() < CConfig::Instance()->GetExtraSlotsRate())
2294 )
2295 {
2296 const time_t now = time(0);
2297 if ( now > (m_tLastRateExtra + 60) )
2298 {
2299 DownloadManagerInfo.slot_use_rate_extra++;
2300 Transfer->SetTransferType(ettRATE_EXTRA);
2301 m_tLastRateExtra = now;
2302 res = true;
2303 }
2304 }
2305
2306 /* check for extra user slots, they are used up even if they already got a free slot above */
2307 if ( CheckUserSlot( Transfer->GetDstNick(), Transfer->GetHubName() ) )
2308 {
2309 if ( res == false )
2310 {
2311 DownloadManagerInfo.slot_use_user++;
2312 Transfer->SetTransferType(ettUSER);
2313 res = true;
2314 }
2315 // else they got a slot already but still used up a granted slot
2316 }
2317
2318 if ( res == false ) // no normal slot granted, allocate special than operator slot
2319 {
2320 if ( Transfer->GetDstNick().IsEmpty() )
2321 {
2322 DPRINTF("WARNING: get a free slot -> remote nick is empty\n");
2323 }
2324 else
2325 {
2326 // no free normal slot - use special slot (lists, small files, leaves)
2327 // set special slot if available
2328 if ( DownloadManagerInfo.slot_use_special < 4 )
2329 {
2330 DownloadManagerInfo.slot_use_special++;
2331 Transfer->SetTransferType(ettSPECIAL);
2332 res = true;
2333 }
2334
2335 // no more special slots - use operator slot (list only)
2336 if ( !res && CConnectionManager::Instance()->IsAdmin(Transfer->GetHubName(),Transfer->GetHubHost(),Transfer->GetDstNick()) )
2337 {
2338 // set operator slot if available
2339 if ( DownloadManagerInfo.slot_use_operator < 4 )
2340 {
2341 DownloadManagerInfo.slot_use_operator++;
2342 Transfer->SetTransferType(ettOPERATOR);
2343 res = true;
2344 }
2345 }
2346 }
2347 }
2348 }
2349 }
2350 // allow all downloads
2351 else
2352 {
2353 res = true;
2354 }
2355
2356 return res;
2357 }
2358
2359 /** */
OptimizeChunks(DCFileChunkObject * FileChunkObject)2360 void CDownloadManager::OptimizeChunks( DCFileChunkObject * FileChunkObject )
2361 {
2362 DCChunkObject *co, *co1;
2363
2364 // get first not locked chunk
2365 co = 0;
2366 while ( (co=FileChunkObject->m_Chunks.Next(co)) != 0 )
2367 {
2368 if ( co->m_eChunkState == ecsFREE )
2369 {
2370 co1 = co;
2371 while ( (co1=FileChunkObject->m_Chunks.Next(co1)) != 0 )
2372 {
2373 if ( co1 == co )
2374 {
2375 continue;
2376 }
2377
2378 if ( co1->m_eChunkState == ecsFREE )
2379 {
2380 if ( co->m_nEnd == co1->m_nStart )
2381 {
2382 co->m_nEnd = co1->m_nEnd;
2383 FileChunkObject->m_Chunks.Del(co1);
2384 co1 = co;
2385 }
2386 else if ( co->m_nStart == co1->m_nEnd )
2387 {
2388 co->m_nStart = co1->m_nStart;
2389 FileChunkObject->m_Chunks.Del(co1);
2390 co1 = co;
2391 }
2392 }
2393 }
2394 }
2395 }
2396
2397 }
2398
2399 /** */
GetNextChunk(CString file,ulonglong * lstart,ulonglong * lend)2400 bool CDownloadManager::GetNextChunk( CString file, ulonglong * lstart, ulonglong * lend )
2401 {
2402 bool res = false;
2403 DCFileChunkObject * FileChunkObject;
2404 DCChunkObject * ChunkObject, *co, *co1, *bigco, *firstco;
2405 ulonglong size;
2406 bool split, standalone;
2407 ulonglong minsegsize;
2408 if ( CConfig::Instance() )
2409 {
2410 minsegsize = CConfig::Instance()->GetMinSegSize();
2411 }
2412 else
2413 {
2414 minsegsize = 1048576;
2415 }
2416
2417 DPRINTF("get the next chunk for '%s'\n",file.Data());
2418
2419 if ( (FileChunkObject = m_pDownloadQueue->GetFileChunkObject(file)) != 0 )
2420 {
2421 OptimizeChunks(FileChunkObject);
2422
2423 co = 0;
2424 ChunkObject = 0;
2425 bigco = 0;
2426 firstco = 0;
2427 size = 0;
2428
2429 // get a free chunk
2430 while ( (ChunkObject=FileChunkObject->m_Chunks.Next(ChunkObject)) != 0 )
2431 {
2432 if ( ChunkObject->m_eChunkState == ecsFREE )
2433 {
2434 // find the biggest chunk
2435 if ( (ChunkObject->m_nEnd-ChunkObject->m_nStart) > size )
2436 {
2437 bigco = ChunkObject;
2438 size = ChunkObject->m_nEnd-ChunkObject->m_nStart;
2439 }
2440 // find the first chunk with nothing before it
2441 standalone = true;
2442 while ( (co=FileChunkObject->m_Chunks.Next(co)) != 0 )
2443 {
2444 if ( co->m_nEnd == ChunkObject->m_nStart )
2445 {
2446 standalone = false;
2447 }
2448 }
2449 if (standalone) {
2450 if ( firstco == 0 || firstco->m_nStart > ChunkObject->m_nStart ) {
2451 firstco = ChunkObject;
2452 }
2453 }
2454 }
2455 }
2456
2457 // prefer the first free chunk to the biggest
2458 if ( firstco != 0 ) {
2459 co = firstco;
2460 } else {
2461 co = bigco;
2462 }
2463
2464 // found a free chunk
2465 if ( co != 0 )
2466 {
2467 split = false;
2468
2469 // split if the half chunk size > max. chunk size
2470 if ( ((co->m_nEnd-co->m_nStart)/2) > minsegsize )
2471 {
2472 ChunkObject = 0;
2473
2474 // check if a running chunk for this chunk
2475 while ( (ChunkObject=FileChunkObject->m_Chunks.Next(ChunkObject)) != 0 )
2476 {
2477 if ( ChunkObject->m_eChunkState == ecsLOCKED )
2478 {
2479 if ( ChunkObject->m_nEnd == co->m_nStart )
2480 {
2481 split = true;
2482 }
2483 }
2484 }
2485 }
2486
2487 ChunkObject = co;
2488
2489 if ( ( (ChunkObject->m_nEnd - ChunkObject->m_nStart) > minsegsize ) && FileChunkObject->m_bMulti )
2490 {
2491 // create a new chunk
2492 co = new DCChunkObject();
2493
2494 // split chunk
2495 if ( (ChunkObject->m_nStart == 0) || (split == false) )
2496 {
2497 co->m_nStart = ChunkObject->m_nStart;
2498 co->m_nEnd = ChunkObject->m_nStart+minsegsize;
2499 ChunkObject->m_nStart += minsegsize;
2500 }
2501 else
2502 {
2503 DPRINTF("CHUNK SET 1: %llu %llu\n",ChunkObject->m_nStart,ChunkObject->m_nEnd);
2504
2505 co->m_nStart = ChunkObject->m_nStart+((ChunkObject->m_nEnd - ChunkObject->m_nStart)/2);
2506
2507 if ( (ChunkObject->m_nEnd-co->m_nStart) > minsegsize )
2508 {
2509 co->m_nEnd = co->m_nStart+minsegsize;
2510 co1 = new DCChunkObject();
2511 co1->m_nStart = co->m_nEnd;
2512 co1->m_nEnd = ChunkObject->m_nEnd;
2513 FileChunkObject->m_Chunks.Add(co1);
2514 DPRINTF("CHUNK SET 2: %llu %llu\n",co1->m_nStart,co1->m_nEnd);
2515 }
2516 else
2517 {
2518 co->m_nEnd = ChunkObject->m_nEnd;
2519 }
2520
2521 ChunkObject->m_nEnd = co->m_nStart;
2522
2523 DPRINTF("CHUNK SET 3: %llu %llu\n",ChunkObject->m_nStart,ChunkObject->m_nEnd);
2524 DPRINTF("CHUNK SET 4: %llu %llu\n",co->m_nStart,co->m_nEnd);
2525 }
2526
2527 co->m_eChunkState = ecsLOCKED;
2528
2529 FileChunkObject->m_Chunks.Add(co);
2530
2531 *lstart = co->m_nStart;
2532 *lend = co->m_nEnd;
2533
2534 DPRINTF("NEW CHUNK SPLIT/LOCKED: %llu %llu\n",*lstart,*lend);
2535
2536 res = true;
2537 }
2538 else
2539 {
2540 ChunkObject->m_eChunkState = ecsLOCKED;
2541
2542 *lstart = ChunkObject->m_nStart;
2543 *lend = ChunkObject->m_nEnd;
2544
2545 DPRINTF("NEW CHUNK LOCKED: %llu %llu\n",*lstart,*lend);
2546
2547 res = true;
2548 }
2549 }
2550 }
2551 else
2552 {
2553 DPRINTF("warning file not found in the chunk list\n");
2554 }
2555
2556 return res;
2557 }
2558
2559 /** 0: not found; 1: found and update; 2: no more chunks (file download ok) */
UpdateChunk(CString file,ulonglong lstart,ulonglong lend,ulonglong lcurrent)2560 int CDownloadManager::UpdateChunk( CString file, ulonglong lstart, ulonglong lend, ulonglong lcurrent )
2561 {
2562 int res = 0;
2563 DCFileChunkObject * FileChunkObject;
2564 DCChunkObject * ChunkObject, *co;
2565
2566 DPRINTF("update chunk for '%s'\n",file.Data());
2567
2568 m_pDownloadQueue->pChunksMutex->Lock();
2569
2570 if ( (FileChunkObject = m_pDownloadQueue->GetFileChunkObject(file)) != 0 )
2571 {
2572 ChunkObject = 0;
2573
2574 // search the chunk
2575 while ( (ChunkObject=FileChunkObject->m_Chunks.Next(ChunkObject)) != 0 )
2576 {
2577 if ( (ChunkObject->m_nStart == lstart) && (ChunkObject->m_nEnd == lend) )
2578 {
2579 // chunk found
2580 res = 1;
2581
2582 if ( ChunkObject->m_eChunkState == ecsFREE )
2583 {
2584 DPRINTF("warning wrong chunk state\n");
2585 }
2586
2587 ChunkObject->m_eChunkState = ecsFREE;
2588
2589 if ( lstart != lcurrent )
2590 {
2591 // update size done
2592 FileChunkObject->m_nSizeDone += (lcurrent-lstart);
2593
2594 DPRINTF("FILESTATE: %llu %llu\n",FileChunkObject->m_nSizeDone,FileChunkObject->m_nSize);
2595
2596 if ( lcurrent == lend )
2597 {
2598 FileChunkObject->m_Chunks.Del(ChunkObject);
2599 ChunkObject = 0;
2600 }
2601 else
2602 {
2603 ChunkObject->m_nStart = lcurrent;
2604 }
2605
2606 if ( FileChunkObject->m_nSizeDone == FileChunkObject->m_nSize )
2607 {
2608 // remove the complete chunk from the list
2609 m_pDownloadQueue->pChunkList->Del(file);
2610 res = 2;
2611 break;
2612 }
2613 }
2614
2615 if ( ChunkObject != 0 )
2616 {
2617 co = 0;
2618 while ( (co=FileChunkObject->m_Chunks.Next(co)) != 0 )
2619 {
2620 if ( co == ChunkObject )
2621 continue;
2622
2623 if ( ChunkObject->m_nEnd == co->m_nStart )
2624 {
2625 if ( co->m_eChunkState == ecsFREE )
2626 {
2627 co->m_nStart = ChunkObject->m_nStart;
2628 FileChunkObject->m_Chunks.Del(ChunkObject);
2629 ChunkObject = co;
2630 DPRINTF("CHUNK FIX1: %llu %llu\n",ChunkObject->m_nStart,ChunkObject->m_nEnd);
2631 }
2632 break;
2633 }
2634 }
2635
2636 co = 0;
2637 while ( (co=FileChunkObject->m_Chunks.Next(co)) != 0 )
2638 {
2639 if ( co == ChunkObject )
2640 continue;
2641
2642 if ( ChunkObject->m_nStart == co->m_nEnd )
2643 {
2644 if ( co->m_eChunkState == ecsFREE )
2645 {
2646 co->m_nEnd = ChunkObject->m_nEnd;
2647 FileChunkObject->m_Chunks.Del(ChunkObject);
2648 ChunkObject = 0;
2649 DPRINTF("CHUNK FIX2: %llu %llu\n",co->m_nStart,co->m_nEnd);
2650 }
2651 break;
2652 }
2653 }
2654 }
2655
2656 break;
2657 }
2658 }
2659 }
2660 else
2661 {
2662 DPRINTF("warning file not found in the chunk list\n");
2663 }
2664
2665 m_pDownloadQueue->pChunksMutex->UnLock();
2666
2667 return res;
2668 }
2669
2670 /** */
GetNewChunkEnd(CString file,ulonglong lstart,ulonglong lend,ulonglong lcurrent,ulonglong * lnstart,ulonglong * lnend)2671 bool CDownloadManager::GetNewChunkEnd( CString file, ulonglong lstart, ulonglong lend, ulonglong lcurrent, ulonglong * lnstart, ulonglong *lnend )
2672 {
2673 m_pDownloadQueue->pChunksMutex->Lock();
2674
2675 bool res = false;
2676 DCFileChunkObject * FileChunkObject;
2677 DCChunkObject * ChunkObject, *co1=0,*co2=0;
2678 ulonglong chunk_size;
2679 ulonglong minsegsize;
2680 if ( CConfig::Instance() )
2681 {
2682 minsegsize = CConfig::Instance()->GetMinSegSize();
2683 }
2684 else
2685 {
2686 minsegsize = 1048576;
2687 }
2688
2689 if ( (FileChunkObject = m_pDownloadQueue->GetFileChunkObject(file)) != 0 )
2690 {
2691 ChunkObject = 0;
2692
2693 while ( (ChunkObject=FileChunkObject->m_Chunks.Next(ChunkObject)) != 0 )
2694 {
2695 if ( (ChunkObject->m_nStart == lstart) && (ChunkObject->m_nEnd == lend) )
2696 {
2697 // start chunk found
2698 co1 = ChunkObject;
2699
2700 if ( co2 )
2701 {
2702 // next chunk is set -> stop search
2703 break;
2704 }
2705 }
2706 else if ( ChunkObject->m_nStart == lend )
2707 {
2708 // next chunk found
2709 if ( ChunkObject->m_eChunkState == ecsLOCKED )
2710 {
2711 // the chunk after the original chunk is locked -> stop search
2712 break;
2713 }
2714 else
2715 {
2716 // set next chunk
2717 co2 = ChunkObject;
2718
2719 if ( co1 )
2720 {
2721 // start chunk is set -> stop search
2722 break;
2723 }
2724 }
2725 }
2726 }
2727
2728 // found start and next chunk
2729 if ( (co1 != 0) && (co2 != 0) )
2730 {
2731 DPRINTF("set new chunk end for '%s'\n",file.Data());
2732
2733 // calc chunk size
2734 if ( (lend-lcurrent) > minsegsize )
2735 chunk_size = minsegsize;
2736 else
2737 chunk_size = minsegsize-(lend-lcurrent);
2738
2739 // if chunk > max chunk split chunk to chunk size
2740 if ( (co2->m_nEnd-co2->m_nStart) > chunk_size )
2741 {
2742 // set new chunk end
2743 co1->m_nEnd += chunk_size;
2744 // set correct new chunk start
2745 co2->m_nStart += chunk_size;
2746 }
2747 else
2748 {
2749 // set new chunk end
2750 co1->m_nEnd = co2->m_nEnd;
2751 // remote the chunk
2752 FileChunkObject->m_Chunks.Del(co2);
2753 }
2754
2755 if ( (lcurrent-lstart) > 0 )
2756 {
2757 FileChunkObject->m_nSizeDone += (lcurrent-lstart);
2758 co1->m_nStart = lcurrent;
2759 }
2760
2761 *lnstart = co1->m_nStart;
2762 *lnend = co1->m_nEnd;
2763
2764 DPRINTF("new chunk end set %llu -> %llu [%llu/%llu]\n",lend,*lnend,(*lnend)-(*lnstart),chunk_size);
2765
2766 res = true;
2767 }
2768 }
2769 else
2770 {
2771 DPRINTF("warning file not found in the chunk list\n");
2772 }
2773
2774 m_pDownloadQueue->pChunksMutex->UnLock();
2775
2776 return res;
2777 }
2778
2779 /** */
SetFile(CTransfer * Transfer)2780 bool CDownloadManager::SetFile( CTransfer * Transfer )
2781 {
2782 bool res;
2783 DCTransferQueueObject * TransferObject;
2784 ulonglong lstart,lend;
2785 int priority = 0;
2786 res = false;
2787
2788 if ( (TransferObject = m_pDownloadQueue->GetUserTransferObject( Transfer->GetDstNick(), Transfer->GetHubName(), Transfer->GetHubHost() )) != 0 )
2789 {
2790 if ( TransferObject->pTransferFileList.Count() > 0 )
2791 {
2792 DCTransferFileObject * TransferFileObject = 0;
2793
2794 while( (priority <= MAX_FILE_PRIORITY) && (TransferFileObject == 0) )
2795 {
2796 while( TransferObject->pTransferFileList.Next(&TransferFileObject) )
2797 {
2798 // check the priority
2799 if ( priority != TransferFileObject->m_nPriority )
2800 continue;
2801
2802 if ( TransferFileObject->m_eState == etfsNONE )
2803 {
2804 DPRINTF("set file: '%s'\n",TransferFileObject->m_sRemoteFile.Data());
2805
2806 CString sPath,sLocalPath,sFile;
2807 CDir dir;
2808
2809 if ( TransferFileObject->m_eMedium == eltFILE )
2810 {
2811 sFile = TransferFileObject->m_sLocalFile;
2812
2813 DPRINTF("DEBUG: file: '%s'\n",sFile.Data());
2814
2815 // extract file
2816 int pos = sFile.FindRev(DIRSEPARATOR);
2817 if( pos != -1 )
2818 {
2819 sPath = sFile.Left(pos);
2820 }
2821
2822 DPRINTF("DEBUG: path: '%s'\n", sPath.Data());
2823
2824 // create the path
2825 if ( dir.CreatePath(sPath) == false )
2826 {
2827 TransferFileObject->m_eState = etfsERROR;
2828 SendFileInfo( TransferObject, TransferFileObject );
2829 SendLogInfo( "Create path failed: " + sPath, Transfer );
2830 DPRINTF("DEBUG: create path failed: '%s'\n", sPath.Data());
2831 }
2832 else
2833 {
2834 DPRINTF("DOWNLOAD: '%s' %llu '%s'\n",
2835 TransferFileObject->m_sRemoteFile.Data(),
2836 TransferFileObject->m_nSize,
2837 sFile.Data());
2838
2839 res = true;
2840 }
2841 }
2842 else
2843 {
2844 res = true;
2845 }
2846
2847 if ( res )
2848 {
2849 // first we create the hash over the first 1MB of a multi download file in a buffer
2850 if ( TransferFileObject->m_bMulti &&
2851 (TransferFileObject->m_stHash.IsEmpty()))
2852 {
2853 DPRINTF("create the hash for the file\n");
2854
2855 Transfer->SetMedium(eltBUFFER);
2856
2857 lstart = 0;
2858 lend = TEST_CHUNK_SIZE;
2859 }
2860 else // get the next chunk of the file
2861 {
2862 if ( TransferFileObject->m_eMedium == eltCLIENTVERSION )
2863 {
2864 DPRINTF("DEBUG: resolve client version ...\n");
2865 lstart = 0;
2866 lend = 0;
2867 }
2868 else if ( TransferFileObject->m_sRemoteFile == DC_USER_FILELIST )
2869 {
2870 lstart = 0;
2871 lend = 0;
2872 }
2873 else if ( GetNextChunk( TransferFileObject->m_sLocalFile, &lstart, &lend ) == false )
2874 {
2875 // no more chunks
2876 DPRINTF("no more chunks ...\n");
2877 continue;
2878 }
2879
2880 Transfer->SetMedium(TransferFileObject->m_eMedium);
2881 }
2882
2883 Transfer->SetDone(etsNONE);
2884
2885 /* This no longer happens because prefixes are removed at the lowest possible level */
2886 CString TTH = TransferFileObject->m_sHash;
2887
2888 /* should be fixed since 0.3.18 and this check is unnecessary */
2889 if ((TTH.Left(4)).ToUpper() == "TTH:")
2890 {
2891 DPRINTF("CDownloadManager::SetFile: Removed TTH: prefix from TTH\n");
2892 TTH = TTH.Mid(4, TTH.Length() - 4);
2893 }
2894
2895 if ( Transfer->StartDownload(TransferFileObject->m_sRemoteFile,lstart,lend,TransferFileObject->m_nSize,lend-lstart,sFile,TTH) == -1 )
2896 {
2897 Transfer->Disconnect();
2898 }
2899 else
2900 {
2901 // mark file as transfered
2902 TransferFileObject->m_eState = etfsTRANSFER;
2903 }
2904 }
2905 else
2906 {
2907 continue;
2908 }
2909
2910 SendFileInfo( TransferObject, TransferFileObject );
2911
2912 break;
2913 }
2914 else
2915 {
2916 // DPRINTF("state file: '%s' %d\n",TransferFileItem->sRemoteName.Data(),TransferFileItem->eState);
2917 }
2918 }
2919
2920 priority++;
2921 }
2922 }
2923 }
2924
2925 if ( res == false )
2926 {
2927 // set disconnect timeout ... save remote slot ;-)
2928 if ( Transfer->GetDone() != etsIDLE )
2929 {
2930 Transfer->SetStartTime(time(0));
2931 Transfer->SetDone(etsIDLE);
2932 }
2933 }
2934
2935 return res;
2936 }
2937
2938 /** */
UpdateFileState(CTransfer * Transfer,eTransferFileState eState)2939 void CDownloadManager::UpdateFileState( CTransfer * Transfer, eTransferFileState eState )
2940 {
2941 DCTransferQueueObject * TransferObject;
2942 DCTransferFileObject * TransferFileObject;
2943
2944 m_pDownloadQueue->pQueueMutex->Lock();
2945
2946 DPRINTF("updatefile\n");
2947 if ( (TransferObject = m_pDownloadQueue->GetUserTransferObject( Transfer->GetDstNick(), Transfer->GetHubName(), Transfer->GetHubHost() )) != 0 )
2948 {
2949 TransferFileObject = m_pDownloadQueue->GetUserFileObject( Transfer->GetDstNick(), Transfer->GetHubName(), Transfer->GetHubHost(), Transfer->GetDstFilename() );
2950
2951 if ( TransferFileObject != 0 )
2952 {
2953 if ( TransferFileObject->m_eState != etfsTRANSFER )
2954 {
2955 DPRINTF("warning, wrong state in updatefile\n");
2956 }
2957 // if this a check hash dl ?
2958 else if ( (Transfer->GetMedium() == eltBUFFER) && TransferFileObject->m_bMulti )
2959 {
2960 DPRINTF("updatefile hash\n");
2961 if ( eState == etfsNONE )
2962 {
2963 if ( (Transfer->GetStartPosition()+Transfer->GetTransfered()) == Transfer->GetEndPosition() )
2964 {
2965 if ( CheckHash(Transfer) )
2966 {
2967 CString logmsg = "Hash ok '";
2968 logmsg += TransferFileObject->m_sRemoteFile;
2969 logmsg += '\'';
2970 SendLogInfo( logmsg, Transfer );
2971
2972 TransferFileObject->m_eState = etfsNONE;
2973
2974 // reconnect if remote dont support chunk dl
2975 if ( Transfer->SupportsChunks() == false )
2976 {
2977 // wan't a reconnect
2978 TransferObject->bReconnect = true;
2979 }
2980 }
2981 else
2982 {
2983 CString logmsg = "Hash failed '";
2984 logmsg += TransferFileObject->m_sRemoteFile;
2985 logmsg += '\'';
2986 SendLogInfo( logmsg, Transfer );
2987 TransferFileObject->m_eState = etfsERROR;
2988 }
2989 }
2990 else
2991 {
2992 TransferFileObject->m_eState = eState;
2993 }
2994 }
2995 else
2996 {
2997 TransferFileObject->m_eState = eState;
2998 }
2999
3000 SendFileInfo( TransferObject, TransferFileObject );
3001 }
3002 else
3003 {
3004 DPRINTF("updatefile normal\n");
3005
3006 int state=0;
3007
3008 TransferFileObject->m_eState = eState;
3009
3010 if ( Transfer->GetMedium() == eltCLIENTVERSION )
3011 {
3012 state = 2;
3013 }
3014 // check if mylist.dclist done
3015 else if ( TransferFileObject->m_sRemoteFile == DC_USER_FILELIST )
3016 {
3017 if ( (Transfer->GetLength() != 0) &&
3018 (Transfer->GetLength() == Transfer->GetTransfered()) )
3019 {
3020 FileListDone( Transfer, TransferFileObject );
3021 state = 2;
3022 }
3023 }
3024 else
3025 {
3026 state = UpdateChunk( TransferFileObject->m_sLocalFile, Transfer->GetStartPosition(),
3027 Transfer->GetEndPosition(), Transfer->GetStartPosition()+Transfer->GetTransfered() );
3028 }
3029
3030 TransferFileObject->m_nSize = Transfer->GetLength();
3031
3032 // download finished
3033 if ( state == 2 )
3034 {
3035 if ( Transfer->GetMedium() != eltCLIENTVERSION )
3036 {
3037 CString logmsg = "Transfer done '";
3038 logmsg += TransferFileObject->m_sRemoteFile;
3039 logmsg += '\'';
3040 SendLogInfo( logmsg, Transfer );
3041 }
3042 SendFileInfo( TransferObject, TransferFileObject, true );
3043 SendTransferInfo( Transfer, false );
3044
3045 // finished downloads are now a log option
3046 if ( (TransferFileObject->m_eMedium == eltFILE) &&
3047 CConfig::Instance()->GetLogFile() &&
3048 CConfig::Instance()->GetLogFinishedDownloads() &&
3049 (TransferFileObject->m_sRemoteFile != DC_USER_FILELIST) )
3050 {
3051 CString logfilemsg = "Transfer done '";
3052 logfilemsg += TransferFileObject->m_sLocalFile;
3053 logfilemsg += '\'';
3054 CLogFile::Write(CConfig::Instance()->GetLogFileName(),eltINFO,logfilemsg);
3055 }
3056
3057 // move the file to the finished path
3058 if ( (TransferFileObject->m_eMedium == eltFILE) && // only files
3059 (CConfig::Instance()->GetDownloadFinishedFolder().NotEmpty()) && // only if dlfolder set
3060 (TransferFileObject->m_sRemoteFile != DC_USER_FILELIST) && // only if this not a filelist
3061 (CDir::ConvertSeparators(TransferFileObject->m_sLocalFile).Find(CDir::ConvertSeparators(CConfig::Instance()->GetDownloadFolder())) == 0) ) // only if the download in the download folder
3062 {
3063 CString s;
3064
3065 // close file
3066 Transfer->CloseFile();
3067
3068 CDir dir(CConfig::Instance()->GetDownloadFinishedFolder());
3069
3070 if ( dir.CreatePath(TransferFileObject->m_sLocalPath) )
3071 {
3072 dir.SetPath(CConfig::Instance()->GetDownloadFinishedFolder()+DIRSEPARATOR+TransferFileObject->m_sLocalPath);
3073 #ifdef WIN32
3074 s = "move ";
3075 s += '"';
3076 s += TransferFileObject->m_sLocalFile;
3077 s += "\" \"";
3078 s += dir.Path();
3079 s += '"';
3080
3081 DPRINTF("move file '%s'\n",s.Data());
3082
3083 if ( system(s.Data()) != 0 )
3084 {
3085 DPRINTF("move failed !\n");
3086 }
3087 #else
3088 s = dir.Path();
3089 s += DIRSEPARATOR;
3090 s += TransferFileObject->m_sLocalFileName;
3091 DPRINTF("move file: '%s' ---> '%s'\n",TransferFileObject->m_sLocalFile.Data(), s.Data());
3092 if ( rename(TransferFileObject->m_sLocalFile.Data(), s.Data()) != 0 )
3093 {
3094 if (errno == EXDEV)
3095 {
3096 // we have to copy it manually
3097 if ( CFile::Copy( TransferFileObject->m_sLocalFile, s ) == false )
3098 {
3099 DPRINTF("move failed !\n");
3100 }
3101 else
3102 {
3103 unlink(TransferFileObject->m_sLocalFile.Data());
3104 }
3105 }
3106 }
3107 #endif
3108 }
3109 else
3110 {
3111 DPRINTF("move failed (create path)!\n");
3112 }
3113 }
3114
3115 if ( TransferFileObject->m_bMulti )
3116 {
3117 // remove all files from the wait queue
3118 RemoveQueueFile(TransferFileObject->m_sLocalFile);
3119 }
3120 else
3121 {
3122 // remove a userlist only from this user/hub
3123 RemoveQueueFile( TransferObject->sNick, TransferObject->sHubName, TransferFileObject->m_sRemoteFile );
3124 }
3125 }
3126 else
3127 {
3128 SendFileInfo( TransferObject, TransferFileObject );
3129 }
3130 }
3131 }
3132 }
3133 else
3134 {
3135 DPRINTF("updatefile no GetUserTransferObject\n");
3136 }
3137
3138 m_pDownloadQueue->pQueueMutex->UnLock();
3139 }
3140
3141 /** */
UpdateBanList(time_t ttimeout)3142 void CDownloadManager::UpdateBanList( time_t ttimeout )
3143 {
3144 DCTransferBanObject * TransferBanObject = 0, * tbo = 0;
3145
3146 // remove old entrys
3147 m_pBanListMutex->Lock();
3148
3149 if ( m_pTransferBanList->Count() > 0 )
3150 {
3151 CString s;
3152
3153 while ( m_pTransferBanList->Next( s, &TransferBanObject ) == 1 )
3154 {
3155 if ( (ttimeout-TransferBanObject->m_tTime) > 180 )
3156 {
3157 m_pTransferBanList->Del(s);
3158 TransferBanObject = tbo;
3159 }
3160 else
3161 {
3162 tbo = TransferBanObject;
3163 }
3164 }
3165 }
3166
3167 m_pBanListMutex->UnLock();
3168 }
3169
3170 /** */
UpdateTransferList(time_t ttimeout)3171 void CDownloadManager::UpdateTransferList( time_t ttimeout )
3172 {
3173 long count,rate,tmprate;
3174 CTransferObject * TransferObject;
3175 CTransferObject *obj,*oobj;
3176 CStringList<CMessageFileTransferRate> * ratelist=0;
3177 CMessageFileTransferRate * filetransferrate;
3178 CList<CTransfer> * transferlist=0;
3179
3180 m_pTransfersMutex->Lock();
3181
3182 count = m_pTransferList->Count();
3183
3184 // check if shutdown ready
3185 if ( (m_eShutdownState == essSHUTDOWN) && (count == 0) )
3186 {
3187 m_eShutdownState = essSHUTDOWNREADY;
3188 }
3189
3190 if ( (ttimeout-m_tUpdateTransferTimeout) >= 1 )
3191 {
3192 // update slots
3193 DownloadManagerInfo.slot_max = CConfig::Instance()->GetMaxUpload();
3194 DownloadManagerInfo.rate_ul_settings = 0;
3195 DownloadManagerInfo.rate_ul_operator = 0;
3196 DownloadManagerInfo.rate_ul_user = 0;
3197 DownloadManagerInfo.rate_ul_special = 0;
3198 DownloadManagerInfo.rate_ul_rate_extra = 0;
3199 DownloadManagerInfo.rate_dl = 0;
3200
3201 UpdateBanList( ttimeout );
3202 }
3203
3204 if ( count > 0 )
3205 {
3206 obj = oobj = 0;
3207
3208 ratelist = new CStringList<CMessageFileTransferRate>();
3209 transferlist = new CList<CTransfer>();
3210
3211 while( m_pTransferList->Next( &obj ) )
3212 {
3213 TransferObject = obj;
3214
3215 // check if user offline and disconnect
3216 if ( (ttimeout-TransferObject->m_UserDisconnectTimeout) > 180 )
3217 {
3218 eCloseType closetype = CConfig::Instance()->GetHubOfflineTransferClose();
3219
3220 TransferObject->m_UserDisconnectTimeout = ttimeout;
3221
3222 if ( CConnectionManager::Instance()->IsHubOnline( TransferObject->m_pTransfer->GetHubName(), TransferObject->m_pTransfer->GetHubHost() ) == ehsONLINE )
3223 {
3224 if ( CConnectionManager::Instance()->IsUserOnline( TransferObject->m_pTransfer->GetDstNick(), TransferObject->m_pTransfer->GetHubName(), TransferObject->m_pTransfer->GetHubHost(), 0 ) == false )
3225 {
3226 if ( (TransferObject->m_pTransfer->GetSrcDirection()==edDOWNLOAD) &&
3227 ( (closetype==ectBOTH) || (closetype==ectDLD) ) )
3228 {
3229 TransferObject->m_pTransfer->Disconnect(true);
3230 CString logmsg = "Disconnect offline user: ";
3231 logmsg += TransferObject->m_pTransfer->GetDstNick();
3232 logmsg += '@';
3233 logmsg += TransferObject->m_pTransfer->GetHubName();
3234 SendLogInfo(logmsg);
3235 }
3236 else if ( (TransferObject->m_pTransfer->GetSrcDirection()==edUPLOAD) &&
3237 ( (closetype==ectBOTH) || (closetype==ectUPLD) ) )
3238 {
3239 TransferObject->m_pTransfer->Disconnect(true);
3240 CString logmsg = "Disconnect offline user: ";
3241 logmsg += TransferObject->m_pTransfer->GetDstNick();
3242 logmsg += '@';
3243 logmsg += TransferObject->m_pTransfer->GetHubName();
3244 SendLogInfo(logmsg);
3245 }
3246 }
3247 }
3248 else
3249 {
3250 //DPRINTF("Not disconnecting user because hub is offline\n");
3251 }
3252 }
3253
3254 // refresh transfer
3255 TransferObject->m_pTransfer->Thread();
3256
3257 if ( (ttimeout-m_tUpdateTransferTimeout) >= 1 )
3258 {
3259 // done==2 set new file or disconnect
3260 if ( (TransferObject->m_pTransfer->GetDone() == etsIDLE) &&
3261 (m_eShutdownState == essNONE) )
3262 {
3263 bool newfile = false;
3264
3265 // set new file on download mode
3266 if ( TransferObject->m_pTransfer->GetSrcDirection() == edDOWNLOAD )
3267 {
3268 while(1)
3269 {
3270 // stop if we cant set a new file
3271 if ( SetFile(TransferObject->m_pTransfer) == false )
3272 {
3273 break;
3274 }
3275
3276 // check for clientcheck
3277 if ( TransferObject->m_pTransfer->GetMedium() == eltCLIENTVERSION )
3278 {
3279 // remove clientcheck from queue (we have the client info at connect)
3280 UpdateFileState(TransferObject->m_pTransfer,etfsNONE);
3281 }
3282 else
3283 {
3284 // new file set successful
3285 newfile = true;
3286 break;
3287 }
3288 }
3289
3290 }
3291
3292 // no new file or another transfer mode
3293 if ( newfile == false )
3294 {
3295 // check timeout for ul/dl
3296 if ( TransferObject->m_pTransfer->GetStartTime() != 0 )
3297 {
3298 if ( (ttimeout-TransferObject->m_pTransfer->GetStartTime()) >= 60 )
3299 {
3300 TransferObject->m_pTransfer->SetStartTime(0);
3301 TransferObject->m_pTransfer->Disconnect(true);
3302 }
3303 }
3304 }
3305
3306 SendTransferInfo(TransferObject->m_pTransfer);
3307
3308 oobj = obj;
3309 }
3310 else if ( TransferObject->m_pTransfer->GetDone() == etsREADY )
3311 {
3312 if ( TransferObject->m_pTransfer->GetDstDirection() == edDOWNLOAD )
3313 {
3314 // TODO: update slot infos etc. in downloadmanager and gui
3315 if ( TransferObject->m_pTransfer->GetTransferType() == ettSETTINGS )
3316 {
3317 if ( DownloadManagerInfo.slot_use_settings > 0 )
3318 DownloadManagerInfo.slot_use_settings--;
3319 }
3320 else if ( TransferObject->m_pTransfer->GetTransferType() == ettOPERATOR )
3321 {
3322 if ( DownloadManagerInfo.slot_use_operator > 0 )
3323 DownloadManagerInfo.slot_use_operator--;
3324 }
3325 else if ( TransferObject->m_pTransfer->GetTransferType() == ettUSER )
3326 {
3327 if ( DownloadManagerInfo.slot_use_user > 0 )
3328 DownloadManagerInfo.slot_use_user--;
3329 }
3330 else if ( TransferObject->m_pTransfer->GetTransferType() == ettSPECIAL )
3331 {
3332 if ( DownloadManagerInfo.slot_use_special > 0 )
3333 DownloadManagerInfo.slot_use_special--;
3334 }
3335 else if ( TransferObject->m_pTransfer->GetTransferType() == ettRATE_EXTRA )
3336 {
3337 if ( DownloadManagerInfo.slot_use_rate_extra > 0 )
3338 {
3339 DownloadManagerInfo.slot_use_rate_extra--;
3340 }
3341 }
3342
3343 // update used slots
3344 CConnectionManager::Instance()->SendMyInfoToConnectedServers();
3345 }
3346
3347 SendTransferInfo( TransferObject->m_pTransfer, true );
3348
3349 // update internal transfer state for this user/hubname
3350 // set to idle (this work only with 1 transfer per user/hubname ...)
3351 DCTransferQueueObject * TransferQueueObject;
3352
3353 if ( TransferObject->m_pTransfer->GetSrcDirection() == edDOWNLOAD )
3354 {
3355 if ( (TransferQueueObject = m_pDownloadQueue->GetUserTransferObject( TransferObject->m_pTransfer->GetDstNick(), TransferObject->m_pTransfer->GetHubName(), TransferObject->m_pTransfer->GetHubHost() )) != 0 )
3356 {
3357 if ( TransferQueueObject->eState == etwsRUN )
3358 {
3359 if ( TransferQueueObject->iConnections > 0 )
3360 TransferQueueObject->iConnections--;
3361 else
3362 DPRINTF("WARNING: UpdateTransferList: RUN:0\n");
3363 if ( TransferQueueObject->iConnections == 0 )
3364 TransferQueueObject->eState = etwsIDLE;
3365 }
3366 else
3367 {
3368 DPRINTF("WARNING: UpdateTransferList: wrong queue state\n");
3369 }
3370
3371 // wan't reconnect ?
3372 if ( TransferQueueObject->bReconnect )
3373 {
3374 TransferQueueObject->tTimeout = 0;
3375 TransferQueueObject->bReconnect = false;
3376 }
3377 else
3378 {
3379 TransferQueueObject->tTimeout = ttimeout;
3380 }
3381
3382 SendFileInfo( TransferQueueObject );
3383 }
3384 }
3385
3386 m_pTransferList->Del( CString::number(TransferObject->m_pTransfer->GetTransferID()) );
3387
3388 obj = oobj;
3389 }
3390 else if ( m_eShutdownState == essNONE )
3391 {
3392 if ( TransferObject->m_pTransfer->GetSrcDirection() == edUPLOAD )
3393 {
3394 switch(TransferObject->m_pTransfer->GetTransferType())
3395 {
3396 case ettSETTINGS:
3397 DownloadManagerInfo.rate_ul_settings += TransferObject->m_pTransfer->GetTransferrate();
3398 break;
3399 case ettOPERATOR:
3400 DownloadManagerInfo.rate_ul_operator += TransferObject->m_pTransfer->GetTransferrate();
3401 break;
3402 case ettUSER:
3403 DownloadManagerInfo.rate_ul_user += TransferObject->m_pTransfer->GetTransferrate();
3404 break;
3405 case ettSPECIAL:
3406 DownloadManagerInfo.rate_ul_special += TransferObject->m_pTransfer->GetTransferrate();
3407 break;
3408 case ettRATE_EXTRA:
3409 DownloadManagerInfo.rate_ul_rate_extra += TransferObject->m_pTransfer->GetTransferrate();
3410 break;
3411 default:
3412 break;
3413 }
3414
3415 SendTransferInfo(TransferObject->m_pTransfer);
3416 }
3417 else if ( TransferObject->m_pTransfer->GetSrcDirection() == edDOWNLOAD )
3418 {
3419 DownloadManagerInfo.rate_dl += TransferObject->m_pTransfer->GetTransferrate();
3420
3421 // create the filetransferratelist
3422 if ( TransferObject->m_pTransfer->GetDstFilename() != DC_USER_FILELIST )
3423 {
3424 filetransferrate = 0;
3425 if ( ratelist->Get( TransferObject->m_pTransfer->GetSrcFilename(), &filetransferrate ) == 0 )
3426 {
3427 filetransferrate->m_nRate += TransferObject->m_pTransfer->GetTransferrate();
3428 }
3429 else
3430 {
3431 filetransferrate = new CMessageFileTransferRate();
3432 filetransferrate->m_sLocalFile = TransferObject->m_pTransfer->GetSrcFilename();
3433 filetransferrate->m_nRate = TransferObject->m_pTransfer->GetTransferrate();
3434
3435 ratelist->Add( TransferObject->m_pTransfer->GetSrcFilename(), filetransferrate );
3436 }
3437 }
3438
3439 transferlist->Add(TransferObject->m_pTransfer);
3440 }
3441 else
3442 {
3443 SendTransferInfo(TransferObject->m_pTransfer);
3444 }
3445
3446 oobj = obj;
3447 }
3448 else
3449 {
3450 oobj = obj;
3451 }
3452 }
3453 }
3454 }
3455
3456
3457 // send all download with global filetransferrate
3458 if ( (ratelist != 0) && (transferlist != 0) )
3459 {
3460 CTransfer *tr=0;
3461 filetransferrate = 0;
3462
3463 while ( (tr=transferlist->Next(0)) != 0 )
3464 {
3465 if ( ratelist->Get( tr->GetSrcFilename(), &filetransferrate ) == 0 )
3466 {
3467 LogMutex.Lock();
3468
3469 CMessageDMTransferObject * to = CreateDMTransferObject(tr);
3470
3471 to->m_nMultiRate = filetransferrate->m_nRate;
3472
3473 if ( DC_DownloadManagerCallBack(to) == -1 )
3474 delete to;
3475
3476 LogMutex.UnLock();
3477 }
3478 else
3479 {
3480 SendTransferInfo(tr);
3481 }
3482
3483 transferlist->Remove(tr);
3484 }
3485
3486 delete ratelist;
3487 delete transferlist;
3488 }
3489
3490 if ( ((ttimeout-m_tUpdateTransferTimeout) >= 1) && (count > 0) )
3491 {
3492 // dynamic upload rate
3493 if ( CConfig::Instance()->GetDynamicUploadRate() &&
3494 (CConfig::Instance()->GetMaxUploadRate() > 0) &&
3495 (DownloadManagerInfo.slot_use_settings > 0) &&
3496 (DownloadManagerInfo.slot_max > 0) &&
3497 (DownloadManagerInfo.rate_ul_settings<(CConfig::Instance()->GetMaxUploadRate()*DownloadManagerInfo.slot_max)) )
3498 {
3499 // calculate max rate for every slot
3500 rate = CConfig::Instance()->GetMaxUploadRate()*DownloadManagerInfo.slot_max;
3501
3502 // this is the max rate for every slot but if a slot use less than
3503 // we give the other slots the "restrate"
3504 rate /= DownloadManagerInfo.slot_use_settings;
3505
3506 if ( rate > 0 )
3507 {
3508 obj = 0;
3509 count = 0;
3510 tmprate = 0;
3511
3512 while( m_pTransferList->Next( &obj ) )
3513 {
3514 TransferObject = obj;
3515
3516 if ( (TransferObject->m_pTransfer->GetDone() == etsNONE) &&
3517 (TransferObject->m_pTransfer->GetSrcDirection() == edUPLOAD) &&
3518 (TransferObject->m_pTransfer->GetTransferType() == ettSETTINGS) )
3519 {
3520 // check if the slot use less than 1/2 of the max rate
3521 if ( (TransferObject->m_pTransfer->GetTransferrate() < (TransferObject->m_pTransfer->GetRate()/2)) && ((ulonglong)rate >= TransferObject->m_pTransfer->GetRate()) )
3522 {
3523 // set the new rate for this transfer (3/4)
3524 TransferObject->m_pTransfer->SetRate((TransferObject->m_pTransfer->GetRate()*3/4));
3525 // give other slots the restrate
3526 tmprate += rate-TransferObject->m_pTransfer->GetRate();
3527 }
3528 // check if the slot use less than 3/4 but more as 1/2 of the current rate we made no changes
3529 else if ( (TransferObject->m_pTransfer->GetTransferrate() < (TransferObject->m_pTransfer->GetRate()*3/4)) && ((ulonglong)rate >= TransferObject->m_pTransfer->GetRate()) )
3530 {
3531 // give other slots the restrate
3532 tmprate += rate-TransferObject->m_pTransfer->GetRate();
3533 }
3534 // all other slots use more as 3/4 or the max rate for a slot is less than the current rate for the transfer
3535 else
3536 {
3537 count++;
3538 tmprate += rate;
3539 }
3540 }
3541 }
3542
3543 // calc new rate
3544 if ( (tmprate > 0) && (count > 0) )
3545 {
3546 tmprate /= count;
3547 obj = 0;
3548
3549 while( m_pTransferList->Next( &obj ) )
3550 {
3551 TransferObject = obj;
3552
3553 if ( (TransferObject->m_pTransfer->GetDone() == etsNONE) &&
3554 (TransferObject->m_pTransfer->GetSrcDirection() == edUPLOAD) )
3555 {
3556 if ( (TransferObject->m_pTransfer->GetTransferrate() >= (TransferObject->m_pTransfer->GetRate()*3/4)) || ((ulonglong)rate < TransferObject->m_pTransfer->GetRate()) )
3557 {
3558 TransferObject->m_pTransfer->SetRate(tmprate);
3559 }
3560 }
3561 }
3562 }
3563 }
3564 }
3565
3566 // send dl manager info
3567 SendDownloadManagerInfo(&DownloadManagerInfo);
3568 }
3569
3570 if ( (ttimeout-m_tUpdateTransferTimeout) >= 1 )
3571 {
3572 // send traffic info
3573 SendTrafficInfo();
3574 }
3575
3576 m_pTransfersMutex->UnLock();
3577 }
3578
3579 /** */
UpdateQueueList(time_t ttimeout)3580 void CDownloadManager::UpdateQueueList( time_t ttimeout )
3581 {
3582 int i;
3583 CString nick;
3584 CStringList<DCTransferQueueObject> * StringList = 0;
3585 CStringList<DCTransferQueueObject> * OldStringList = 0;
3586 CList<DCHubObject> hublist;
3587 DCHubObject * HubObject1 = 0, * HubObject2 = 0;
3588 CString hubname;
3589
3590 while( m_pDownloadQueue->pQueue->Next( nick, &StringList) )
3591 {
3592 DCTransferQueueObject * TransferObject = 0;
3593
3594 while( StringList->Next( &TransferObject) )
3595 {
3596 // check for empty filelist
3597 if ( TransferObject->pTransferFileList.Count() == 0 )
3598 {
3599 // empty filelist and no connections
3600 if ( TransferObject->iConnections == 0 )
3601 {
3602 // remove from queue
3603 SendFileInfo( TransferObject, 0, true );
3604 StringList->Del(TransferObject->sHubName);
3605 }
3606 break;
3607 }
3608 // handle wait state
3609 else if ( (TransferObject->eState == etwsWAIT) && (m_eShutdownState == essNONE) )
3610 {
3611 // check response timeout
3612 if ( (ttimeout-TransferObject->tTimeout) >= CConfig::Instance()->GetTransferResponseTimeout() )
3613 {
3614 // set timeout
3615 TransferObject->eState = etwsIDLE;
3616 TransferObject->tTimeout = ttimeout;
3617 SendFileInfo( TransferObject );
3618 }
3619 }
3620 // handle none wait state
3621 else if ( (m_eShutdownState == essNONE) &&
3622 ( (TransferObject->eState == etwsIDLE) ||
3623 (TransferObject->eState == etwsHUBOFFLINE) ||
3624 (TransferObject->eState == etwsUSEROFFLINE) ||
3625 (TransferObject->eState == etwsUSERBUSY) ||
3626 (TransferObject->eState == etwsSENDERROR) ) )
3627 {
3628
3629 // idle state ... check for timeout to reconnect
3630 if ( TransferObject->tTimeout == 0 )
3631 {
3632 // check for max download rate before new connection start
3633 if ( !((CConfig::Instance()->GetMaxDownloadRate() != 0) &&
3634 (CConfig::Instance()->GetMaxDownloadRate() < DownloadManagerInfo.rate_dl)) )
3635 {
3636 // reset hubname
3637 hubname = TransferObject->sHubName;
3638
3639 // update internal hublist
3640 if ( CConnectionManager::Instance()->IsUserOnline( TransferObject->sNick, CString(), CString(), &hublist ) )
3641 {
3642 DPRINTF("user is online on:\n");
3643
3644 HubObject1 = 0;
3645 while( (HubObject1=hublist.Next(HubObject1)) != 0 )
3646 {
3647 DPRINTF("'%s' '%s'\n",HubObject1->m_sHubName.Data(),HubObject1->m_sHubHost.Data());
3648
3649 HubObject2 = 0;
3650 while( (HubObject2=TransferObject->pHubList.Next(HubObject2)) != 0 )
3651 {
3652 if ( HubObject1->m_sHubName == HubObject2->m_sHubName )
3653 break;
3654 }
3655
3656 // add new entry
3657 if ( HubObject2 == 0 )
3658 {
3659 DPRINTF("NEW '%s' '%s'\n",HubObject1->m_sHubName.Data(),HubObject1->m_sHubHost.Data());
3660 HubObject2 = new DCHubObject();
3661 HubObject2->m_sHubName = HubObject1->m_sHubName;
3662 HubObject2->m_sHubHost = HubObject1->m_sHubHost;
3663 HubObject2->m_bActive = true;
3664
3665 TransferObject->pHubList.Add(HubObject2);
3666 }
3667 else // set entry to connect
3668 {
3669 if ( (hubname.IsEmpty()) && HubObject2->m_bActive )
3670 {
3671 DPRINTF("USE '%s'\n",HubObject2->m_sHubName.Data());
3672 hubname = HubObject2->m_sHubName;
3673 }
3674 }
3675 }
3676
3677 hublist.Clear();
3678 }
3679
3680 // check for available files
3681 DCTransferFileObject * TransferFileObject = 0;
3682
3683 while( TransferObject->pTransferFileList.Next( &TransferFileObject ) )
3684 {
3685 if ( TransferFileObject->m_eState == etfsNONE )
3686 {
3687 break;
3688 }
3689 }
3690
3691 if ( TransferFileObject != 0 )
3692 {
3693 // send connection request to the hub
3694 i = CConnectionManager::Instance()->SendConnectionRequest( TransferObject->sNick, hubname, TransferObject->sHubHost );
3695
3696 switch (i)
3697 {
3698 case 0:
3699 TransferObject->eState = etwsWAIT;
3700 break;
3701 case -1:
3702 TransferObject->eState = etwsUSEROFFLINE;
3703 break;
3704 case -2:
3705 case -3:
3706 TransferObject->eState = etwsHUBOFFLINE;
3707 break;
3708 case -4:
3709 TransferObject->eState = etwsSENDERROR;
3710 break;
3711 default:
3712 break;
3713 }
3714 }
3715 }
3716
3717 // update timeout
3718 TransferObject->tTimeout = ttimeout;
3719 // send info
3720 SendFileInfo( TransferObject );
3721 }
3722 // check resend timeout
3723 else if ( (ttimeout-TransferObject->tTimeout) >= CConfig::Instance()->GetTransferResendTimeout() )
3724 {
3725 // reset timeout
3726 TransferObject->tTimeout = 0;
3727 // send info
3728 SendFileInfo( TransferObject );
3729 }
3730 }
3731 }
3732
3733 // remove nick on empty list
3734 if ( StringList->Count() == 0 )
3735 {
3736 m_pDownloadQueue->pQueue->Del(nick);
3737 StringList = OldStringList;
3738 }
3739 else
3740 {
3741 OldStringList = StringList;
3742 }
3743 }
3744 }
3745
3746 /** */
InitSearch(time_t)3747 bool CDownloadManager::InitSearch( time_t /*ttimeout*/ )
3748 {
3749 CStringList<DCTransferQueueObject> * StringList = 0;
3750
3751 // clear searchlist
3752 // TODO: we can leave it and search again on the last break,
3753 // but we need a check against the current queue (traffic)
3754 m_pSearchList->Clear();
3755 m_pSearchQueryList->Clear();
3756
3757 if ( !CSearchManager::Instance() )
3758 {
3759 return false;
3760 }
3761
3762 m_pDownloadQueue->pQueueMutex->Lock();
3763
3764 while( m_pDownloadQueue->pQueue->Next( &StringList ) )
3765 {
3766 DCTransferQueueObject * TransferObject = 0;
3767
3768 while( StringList->Next( &TransferObject ) )
3769 {
3770 DCTransferFileObject * TransferFileObject = 0;
3771
3772 while( TransferObject->pTransferFileList.Next( &TransferFileObject ) )
3773 {
3774 if ( TransferFileObject->m_bMulti && // only if md enabled
3775 TransferFileObject->m_sHash.NotEmpty() && // only if we have a TTH
3776 (TransferFileObject->m_eMedium == eltFILE) ) // only if medium file
3777 {
3778 bool dupe = false;
3779 CMessageSearchResult * it = 0;
3780 while ( (it = m_pSearchList->Next(it)) != 0 )
3781 {
3782 if ( it->m_sHash == TransferFileObject->m_sHash )
3783 {
3784 dupe = true;
3785 break;
3786 }
3787 }
3788
3789 if ( dupe )
3790 {
3791 continue;
3792 }
3793
3794 CMessageSearchResult * msg = new CMessageSearchResult();
3795
3796 msg->m_nSize = TransferFileObject->m_nSize;
3797 msg->m_sFile = TransferFileObject->m_sRemoteFile;
3798 msg->m_sNick = TransferObject->sNick;
3799 msg->m_sHubName = TransferObject->sHubName;
3800 msg->m_sHash = TransferFileObject->m_sHash;
3801
3802 CMessageSearchFile * smsg = new CMessageSearchFile();
3803
3804 smsg->m_sString = TransferFileObject->m_sHash;
3805 smsg->m_eFileType = eftHASH;
3806 smsg->m_bLocal = (CConfig::Instance()->GetMode() == ecmPASSIVE);
3807 /* CClient sets the source (nick or IP) before sending the search */
3808
3809 m_pSearchList->Add(msg);
3810 m_pSearchQueryList->Add(smsg);
3811 }
3812 }
3813 }
3814 }
3815
3816 m_pDownloadQueue->pQueueMutex->UnLock();
3817
3818 if ( m_pSearchList->Count() <= 0 )
3819 {
3820 return false;
3821 }
3822
3823 if ( CSearchManager::Instance()->StartSearch(esmCONNECTEDALL,estyEXTERNAL,m_pSearchQueryList,0) != eseNONE )
3824 {
3825 return false;
3826 }
3827
3828 return true;
3829 }
3830
3831 /** thread callbackfunction */
Callback()3832 int CDownloadManager::Callback()
3833 {
3834 int i;
3835 time_t ttimeout;
3836
3837 if ( m_eShutdownState == essSHUTDOWNREADY )
3838 {
3839 return 0;
3840 }
3841
3842 ttimeout = time(0);
3843
3844 if ( m_eShutdownState == essNONE )
3845 {
3846 // save queue
3847 i = CConfig::Instance()->GetDownloadQueueTime();
3848
3849 if ( i > 0 )
3850 {
3851 i *= 60;
3852
3853 if ( (ttimeout-m_tDownloadQueueTimeout) > i )
3854 {
3855 DLM_SaveQueue();
3856 m_tDownloadQueueTimeout = ttimeout;
3857 }
3858 }
3859 }
3860
3861 // update the transfer list
3862 UpdateTransferList(ttimeout);
3863
3864 // update the queue list
3865 if ( (ttimeout-m_tUpdateTransferTimeout) >= 1 )
3866 {
3867 m_pDownloadQueue->pQueueMutex->Lock();
3868
3869 if ( m_pDownloadQueue->pQueue->Count() > 0 )
3870 {
3871 UpdateQueueList(ttimeout);
3872 }
3873
3874 m_pDownloadQueue->pQueueMutex->UnLock();
3875 }
3876
3877 /*
3878 * If dclib sent a ConnectToMe but there was no response,
3879 * the entry was never removed from m_pTransferWaitList.
3880 * m_pTransferWaitList is limited to 250 entries, after which
3881 * no more transfers will be allowed, i.e. if you had 250 entries
3882 * stuck in it you had to restart valknut.
3883 */
3884 if ( (ttimeout-m_tWaitListCleaned) >= 60 )
3885 {
3886 m_pWaitListMutex->Lock();
3887
3888 DCTransferWait *tw = 0, *tw_prev = 0;
3889 int max_age = CConfig::Instance()->GetTransferResendTimeout() * 5;
3890
3891 if ( max_age < 5*60 )
3892 {
3893 max_age = 5*60;
3894 }
3895
3896 while ( (tw = m_pTransferWaitList->Next(tw)) != 0 )
3897 {
3898 /*
3899 * dclib 0.3.23 fills in the empty info, an
3900 * empty nick or user ip means this transfer
3901 * has not been established.
3902 */
3903 if ( tw->sNick.IsEmpty() || tw->sUserHost.IsEmpty() )
3904 {
3905 if ( (ttimeout - tw->tTimeout) > max_age )
3906 {
3907 DPRINTF("Wait on %s/%s expired\n",tw->sNick.Data(),tw->sUserHost.Data());
3908 m_pTransferWaitList->Del(tw);
3909 tw = tw_prev;
3910 }
3911 }
3912
3913 tw_prev = tw;
3914 }
3915
3916 m_pWaitListMutex->UnLock();
3917
3918 m_tWaitListCleaned = ttimeout;
3919 }
3920
3921 if ( CConfig::Instance()->GetTransferAutoSearch() &&
3922 CSearchManager::Instance() )
3923 {
3924 // if there is no search running and the timeout is not set it can be set
3925 // but if the user searches the timeout must be unset and not be reset until the user
3926 // has finished searching
3927 if ( (m_tHubSearchTimeout == 0) && (CSearchManager::Instance()->SearchType() == estyNONE) )
3928 {
3929 // start countdown
3930 m_tHubSearchTimeout = ttimeout;
3931 }
3932 else if ( (m_tHubSearchTimeout != 0) && ((CSearchManager::Instance()->SearchType() == estySINGLE) || (CSearchManager::Instance()->SearchType() == estyMULTI)) )
3933 {
3934 // stop countdown
3935 m_tHubSearchTimeout = 0;
3936 }
3937
3938 // search for new sources
3939 if ( (m_tHubSearchTimeout != 0) && (ttimeout-m_tHubSearchTimeout) >= CConfig::Instance()->GetAutoSearchInterval() )
3940 {
3941 DPRINTF("init search\n");
3942
3943 if ( InitSearch(ttimeout) == false )
3944 {
3945 DPRINTF("failed\n");
3946 m_tHubSearchTimeout = ttimeout;
3947 }
3948 else
3949 {
3950 m_tHubSearchTimeout = 0;
3951 }
3952 }
3953 }
3954
3955 // update timeout
3956 m_tUpdateTransferTimeout = ttimeout;
3957
3958 return 0;
3959 }
3960
3961 /** Called directly by either of the listen managers */
ListenCallbackHandler(int handle,bool crypto)3962 int CDownloadManager::ListenCallbackHandler( int handle, bool crypto )
3963 {
3964 bool disc = false;
3965
3966 if ( m_eShutdownState == essNONE )
3967 {
3968 m_pWaitListMutex->Lock();
3969
3970 if ( m_pTransferWaitList->Count() == 0 )
3971 {
3972 // no waiting transfers, disconnect incoming connection
3973 disc = true;
3974 }
3975
3976 m_pWaitListMutex->UnLock();
3977 }
3978 else
3979 {
3980 // dont accept connections on shutdown state
3981 disc = true;
3982 }
3983
3984 if ( disc )
3985 {
3986 #ifdef WIN32
3987 closesocket(handle);
3988 #else
3989 close(handle);
3990 #endif
3991 handle = -1;
3992 }
3993
3994 if ( handle == -1 )
3995 {
3996 return -1;
3997 }
3998
3999 CTransferObject * TransferObject = new CTransferObject();
4000 TransferObject->m_pTransfer = new CTransfer(true);
4001
4002 if ( crypto )
4003 {
4004 if ( TransferObject->m_pTransfer->ChangeSocketMode( esmFULLSSLSERVER, CConfig::Instance()->GetTransferCert(), CConfig::Instance()->GetTransferKey() ) == false )
4005 {
4006 DPRINTF("New transfer change to SSL server mode failed\n");
4007 delete TransferObject;
4008 return -1;
4009 }
4010 }
4011
4012 TransferObject->m_pTransfer->SetTransferID( GetNewID() );
4013 TransferObject->m_pTransfer->SetRate( CConfig::Instance()->GetMaxUploadRate() );
4014 TransferObject->m_pTransfer->SetCallBackFunction( new CCallback2<CDownloadManager, CTransfer, CDCMessage*>( this, &CDownloadManager::DM_TransferCallBack ) );
4015
4016 if ( TransferObject->m_pTransfer->SetSocket(handle) == 0 )
4017 {
4018 CString logmsg = "Incoming connection from '";
4019 logmsg += TransferObject->m_pTransfer->GetHost();
4020 logmsg += '\'';
4021 SendLogInfo(logmsg);
4022
4023 m_pTransfersMutex->Lock();
4024 m_pTransferList->Add( CString::number(TransferObject->m_pTransfer->GetTransferID()), TransferObject );
4025 m_pTransfersMutex->UnLock();
4026 }
4027 else
4028 {
4029 delete TransferObject;
4030 #ifdef WIN32
4031 closesocket(handle);
4032 #else
4033 close(handle);
4034 #endif
4035 }
4036
4037 return 0;
4038 }
4039
4040 /** */
DM_TransferCallBack(CTransfer * Transfer,CDCMessage * DCMsg)4041 int CDownloadManager::DM_TransferCallBack( CTransfer * Transfer, CDCMessage * DCMsg )
4042 {
4043 TransferCallBackMutex.Lock();
4044
4045 CByteArray ba;
4046 CString s,r;
4047 ulonglong len;
4048 CDir dir;
4049 bool remove,bdirec;
4050 eShareBufferType stype;
4051 eDirection direction;
4052
4053 switch ( DCMsg->m_eType )
4054 {
4055 case DC_MESSAGE_MYNICK:
4056 {
4057 // check with the nick for download or upload
4058 direction = CheckWaitTransfer( Transfer );
4059 Transfer->SetSrcDirection(direction);
4060
4061 DCMessageConnectClient mcc;
4062 mcc.m_sHubHost = Transfer->GetHost();
4063 CConnectionManager::Instance()->SetUserTransferInfo( Transfer->GetHubName(), Transfer->GetHubHost(), Transfer->GetDstNick(), &mcc );
4064
4065 break;
4066 }
4067
4068 case DC_MESSAGE_GET:
4069 {
4070 // remote want a file ...
4071 CMessageGet * msg = (CMessageGet*)DCMsg;
4072
4073 if ( (Transfer->GetSrcDirection() == edUPLOAD) &&
4074 (Transfer->GetDstDirection() == edDOWNLOAD) )
4075 {
4076 // reset done flags
4077 Transfer->SetDone(etsNONE);
4078
4079 // send a log info
4080 CString logmsg = "Upload: ";
4081 logmsg += msg->m_sFilename;
4082 logmsg += " (";
4083 logmsg += CString::number(msg->m_nPos);
4084 logmsg += '/';
4085 logmsg += CString::number(msg->m_nSize);
4086 logmsg += ')';
4087 SendLogInfo( logmsg, Transfer );
4088
4089 stype = esbtNONE;
4090
4091 if ( msg->m_sFilename == DC_USER_FILELIST_HE3 )
4092 {
4093 stype = esbtHE3;
4094 }
4095 else if ( msg->m_sFilename == DC_USER_FILELIST_BZ )
4096 {
4097 stype = esbtBZ;
4098 }
4099 else if ( msg->m_sFilename == DC_USER_FILELIST_XMLBZ )
4100 {
4101 stype = esbtXMLBZ;
4102 }
4103 else if ( msg->m_sFilename == DC_USER_FILELIST_XML )
4104 {
4105 stype = esbtXML;
4106 }
4107 else if ( Transfer->GetTransferType() == ettOPERATOR )
4108 {
4109 SendLogInfo( "Operator Transfer not for the filelist", Transfer );
4110 Transfer->SendMaxedOut();
4111 Transfer->Disconnect(true);
4112 break;
4113 }
4114
4115 // check special transfer file size
4116 if ( stype != esbtNONE )
4117 {
4118 if ( (CFileManager::Instance()->GetShareBuffer( stype, &ba ) == 0) && (ba.Size() > 0) )
4119 {
4120 // set send buffer
4121 Transfer->SetBuffer(&ba);
4122 // set local transfer medium to buffer
4123 Transfer->SetMedium(eltBUFFER);
4124 // start upload
4125 if ( Transfer->StartUpload( msg->m_sFilename, ba.Size(), msg->m_nPos-1, 0, msg->m_sFilename, msg->m_bUGet, false, CString(), msg->m_bZLib ) == -1 )
4126 {
4127 Transfer->Disconnect(true);
4128 }
4129 }
4130 else
4131 {
4132 Transfer->SendError("File Not Available");
4133 SendLogInfo( "Upload (no sharebuffer): " + msg->m_sFilename, Transfer );
4134 }
4135 }
4136 else // remote download from the share ...
4137 {
4138 // search the wanted file in the share
4139 s = CConfig::Instance()->AliasToPath(msg->m_sFilename);
4140 if ( s.IsEmpty() )
4141 {
4142 Transfer->SendError("File Not Available");
4143
4144 SendLogInfo( "Upload (File Not Available): " + msg->m_sFilename, Transfer );
4145 }
4146 else
4147 {
4148 // file found, check filesize
4149 len = dir.getFileSize(s,false);
4150
4151 if ( msg->m_nPos > len ) // if the wanted filepos > local length send an error
4152 {
4153 Transfer->SendError("File allready download.");
4154 }
4155 else if ( msg->m_nPos == 0 ) // we begin at 1 (see dc protocoll)
4156 {
4157 Transfer->SendError("Wrong file position.");
4158 }
4159 else // upload the wanted file ...
4160 {
4161 // special transfer only for files <= Configured small file size
4162 if ( (Transfer->GetTransferType() == ettSPECIAL) &&
4163 (len > (CConfig::Instance()->GetSmallFileSize())) )
4164 {
4165 // disconnect ...
4166 SendLogInfo( "Special Transfer not for files > " + CUtils::GetSizeString( CConfig::Instance()->GetSmallFileSize(), euAUTO ), Transfer );
4167 Transfer->SendMaxedOut();
4168 Transfer->Disconnect(true);
4169 }
4170 else
4171 {
4172 // set local transfer medium to buffer
4173 Transfer->SetMedium(eltFILE);
4174 // start upload
4175 if ( Transfer->StartUpload( msg->m_sFilename, len, msg->m_nPos-1, msg->m_nSize, s, msg->m_bUGet, false, CString(), msg->m_bZLib ) == -1 )
4176 {
4177 Transfer->Disconnect(true);
4178 }
4179 }
4180 }
4181 }
4182 }
4183 }
4184 else
4185 {
4186 SendLogInfo( "Warning wrong mode", Transfer );
4187 Transfer->Disconnect(true);
4188 }
4189
4190 break;
4191 }
4192
4193 case DC_MESSAGE_ADCGET:
4194 {
4195 // remote want a file by TTH (or files.xml.bz2)
4196 CMessageADCGet * msg = (CMessageADCGet*)DCMsg;
4197
4198 if ( (Transfer->GetSrcDirection() == edUPLOAD) &&
4199 (Transfer->GetDstDirection() == edDOWNLOAD) )
4200 {
4201 // reset done flags
4202 Transfer->SetDone(etsNONE);
4203
4204 if ( msg->m_eADCType == eAdcTTHL )
4205 {
4206 if ( Transfer->GetTransferType() == ettOPERATOR )
4207 {
4208 SendLogInfo( "Operator Transfer not for the filelist", Transfer );
4209 Transfer->SendMaxedOut();
4210 Transfer->Disconnect(true);
4211 }
4212 else
4213 {
4214 CByteArray * leaves = CFileManager::Instance()->GetHashLeaves( msg->m_sTTH );
4215 if ( leaves )
4216 {
4217 Transfer->SetMedium(eltTTHL);
4218
4219 const unsigned long lsize = leaves->Size();
4220
4221 Transfer->ClearAndAppendBuffer( leaves->Data(), lsize );
4222 delete leaves;
4223
4224 CString logmsg = "Send leaves for ";
4225 logmsg += msg->m_sTTH;
4226 logmsg += " (";
4227 logmsg += CString::number(msg->m_nPos);
4228 logmsg += '/';
4229 logmsg += CString::number(lsize);
4230 logmsg += ')';
4231 SendLogInfo( logmsg, Transfer );
4232
4233 // start upload
4234 if ( Transfer->StartUpload( CString(), lsize, msg->m_nPos, lsize, CString(), false, true, msg->m_sTTH, msg->m_bZlib ) == -1 )
4235 {
4236 Transfer->Disconnect(true);
4237 }
4238 }
4239 else
4240 {
4241 /* alternatively could base32 decode the TTH and send those 24 bytes */
4242 DPRINTF("Hash leaves not found for %s\n", msg->m_sTTH.Data());
4243 SendLogInfo( "Hash leaves not found for " + msg->m_sTTH, Transfer );
4244 Transfer->SendError("File Not Available");
4245 Transfer->Disconnect(true);
4246 }
4247 }
4248 break;
4249 }
4250 else if ( msg->m_eADCType == eAdcList )
4251 {
4252 Transfer->SetMedium(eltLIST);
4253
4254 CString displayname = "Listing for ";
4255 displayname += msg->m_sFile;
4256
4257 CString listing;
4258 /*
4259 * FIXME where do we get the depth from? msg->m_nPos is always 0.
4260 * It doesn't really matter because we are allowed to send
4261 * less than the requested depth.
4262 */
4263 CFileManager::Instance()->GetPartialListing( msg->m_sFile, listing );
4264
4265 if ( listing.IsEmpty() )
4266 {
4267 SendLogInfo( "Upload (File Not Available): " + displayname, Transfer );
4268 Transfer->SendError("File Not Available");
4269 Transfer->Disconnect(true);
4270 }
4271 else
4272 {
4273 CString logmsg = "Upload: ";
4274 logmsg += displayname;
4275 logmsg += " (";
4276 logmsg += CString::number(msg->m_nPos);
4277 logmsg += '/';
4278 logmsg += CString::number(listing.Length());
4279 logmsg += ')';
4280 SendLogInfo( logmsg, Transfer );
4281
4282 Transfer->ClearAndAppendBuffer( (const unsigned char*) listing.Data(), listing.Length() );
4283
4284 if ( Transfer->StartUpload(
4285 msg->m_sFile,
4286 listing.Length(),
4287 msg->m_nPos,
4288 listing.Length(),
4289 displayname,
4290 false,
4291 true,
4292 CString(),
4293 msg->m_bZlib
4294 ) == -1 )
4295 {
4296 Transfer->Disconnect(true);
4297 }
4298 }
4299
4300 break;
4301 }
4302 else if ( msg->m_eADCType != eAdcFile )
4303 {
4304 CString logmsg = "Unknown ADCGET transfer type ";
4305 logmsg += CString::number(msg->m_eADCType);
4306
4307 SendLogInfo( logmsg, Transfer );
4308
4309 Transfer->SendError(logmsg);
4310
4311 Transfer->Disconnect();
4312
4313 break;
4314 }
4315
4316 stype = esbtNONE;
4317
4318 if ( msg->m_sFile == DC_USER_FILELIST_XMLBZ )
4319 {
4320 stype = esbtXMLBZ;
4321 }
4322 else if ( msg->m_sFile == DC_USER_FILELIST_XML )
4323 {
4324 stype = esbtXML;
4325 }
4326 else if ( Transfer->GetTransferType() == ettOPERATOR )
4327 {
4328 SendLogInfo( "Operator Transfer not for the filelist", Transfer );
4329 Transfer->SendMaxedOut();
4330 Transfer->Disconnect(true);
4331 break;
4332 }
4333
4334 // check special transfer file size
4335 if ( stype != esbtNONE )
4336 {
4337 if ( (CFileManager::Instance()->GetShareBuffer( stype, &ba ) == 0) && (ba.Size() > 0) )
4338 {
4339 // set send buffer
4340 Transfer->SetBuffer(&ba);
4341 // set local transfer medium to buffer
4342 Transfer->SetMedium(eltBUFFER);
4343 // start upload
4344
4345 /* Filelists always start at 0 */
4346 CString logmsg = "Upload: ";
4347 logmsg += msg->m_sFile;
4348 logmsg += " (0/";
4349 logmsg += CString::number(ba.Size());
4350 logmsg += ')';
4351 SendLogInfo( logmsg, Transfer );
4352
4353 if ( Transfer->StartUpload( msg->m_sFile, ba.Size(), msg->m_nPos, 0, msg->m_sFile, false, true, CString(), msg->m_bZlib ) == -1 )
4354 {
4355 Transfer->Disconnect(true);
4356 }
4357 }
4358 else
4359 {
4360 Transfer->SendError("File Not Available");
4361
4362 SendLogInfo( "Upload (no sharebuffer): " + msg->m_sFile, Transfer );
4363 }
4364 }
4365 else // remote download from the share ...
4366 {
4367 CString fileName;
4368
4369 if ( msg->m_sTTH.IsEmpty() )
4370 {
4371 DPRINTF("Warning! ADCGet without TTH is undocumented behaviour!\n");
4372 if ( msg->m_sFile.NotEmpty() && (msg->m_sFile.Data()[0] == '/') )
4373 {
4374 // DPRINTF("Warning! Removing leading / from filename for ADCGet without TTH\n");
4375 fileName = msg->m_sFile.Mid(1, msg->m_sFile.Length() - 1);
4376 }
4377 else
4378 {
4379 fileName = msg->m_sFile;
4380 }
4381
4382 CString logmsg = "Upload: ";
4383 logmsg += fileName;
4384 logmsg += " (";
4385 logmsg += CString::number(msg->m_nPos);
4386 logmsg += '/';
4387 logmsg += CString::number(msg->m_nSize);
4388 logmsg += ')';
4389 SendLogInfo( logmsg, Transfer );
4390 }
4391 else
4392 {
4393 // search the share for the file matching the TTH, the "TTH/" prefix is now added/removed at a lower level
4394 std::set<unsigned long> * results = CFileManager::Instance()->SearchHash( msg->m_sTTH );
4395
4396 if ( (results == 0) || (results->empty()) )
4397 {
4398 Transfer->SendError("File Not Available");
4399 SendLogInfo( "Upload: No file found for TTH:" + msg->m_sTTH, Transfer );
4400
4401 delete results;
4402
4403 break;
4404 }
4405 else
4406 {
4407 if ( results->size() > 1 )
4408 {
4409 SendLogInfo( "Upload: Warning: Multiple files match TTH:" + msg->m_sTTH, Transfer );
4410 }
4411
4412 fileName = CFileManager::Instance()->GetFileName(*(results->begin()));
4413 delete results;
4414
4415 CString logmsg = "Upload: ";
4416 logmsg += fileName;
4417 logmsg += " (";
4418 logmsg += msg->m_sTTH;
4419 logmsg += ") (";
4420 logmsg += CString::number(msg->m_nPos);
4421 logmsg += '/';
4422 logmsg += CString::number(msg->m_nSize);
4423 logmsg += ')';
4424 SendLogInfo( logmsg, Transfer );
4425 }
4426 }
4427
4428 s = CConfig::Instance()->AliasToPath(fileName);
4429 if ( s.IsEmpty() )
4430 {
4431 DPRINTF("Error: didn't find path to file from share alias!\n");
4432 Transfer->SendError("File Not Available");
4433 SendLogInfo( "Upload: File Not Available: " + fileName, Transfer );
4434 }
4435 else
4436 {
4437 // file found, check filesize
4438 len = dir.getFileSize(s,false);
4439
4440 if ( msg->m_nSize == -1 )
4441 {
4442 msg->m_nSize = len - msg->m_nPos;
4443 }
4444
4445 if ( msg->m_nPos > len ) // if the wanted filepos > local length send an error
4446 {
4447 Transfer->SendError("File already downloaded.");
4448 }
4449 else // upload the wanted file ...
4450 {
4451 // special transfer only for files <= Configured small file size
4452 if ( (Transfer->GetTransferType() == ettSPECIAL) &&
4453 (len > (CConfig::Instance()->GetSmallFileSize())) )
4454 {
4455 // disconnect ...
4456 SendLogInfo( "Special Transfer not for files > " + CUtils::GetSizeString( CConfig::Instance()->GetSmallFileSize(), euAUTO ), Transfer );
4457 Transfer->SendMaxedOut();
4458 Transfer->Disconnect(true);
4459 }
4460 else
4461 {
4462 Transfer->SetMedium(eltFILE);
4463
4464 // start upload
4465 if ( Transfer->StartUpload( fileName, len, msg->m_nPos, msg->m_nSize, s, false, true, msg->m_sTTH, msg->m_bZlib ) == -1 )
4466 {
4467 Transfer->Disconnect(true);
4468 }
4469 }
4470 }
4471 }
4472 }
4473 }
4474 else
4475 {
4476 SendLogInfo( "Warning wrong mode", Transfer );
4477 Transfer->Disconnect(true);
4478 }
4479
4480 break;
4481 }
4482
4483 case DC_MESSAGE_DIRECTION:
4484 {
4485 break;
4486 }
4487
4488 case DC_MESSAGE_KEY:
4489 {
4490 // direction message ...
4491 //CMessageDirection * msg = (CMessageDirection*)DCMsg;
4492 bdirec = false;
4493
4494 DPRINTF("DIRECTION: level: LOCAL: %d REMOTE: %d\n",Transfer->GetSrcLevel(), Transfer->GetDstLevel() );
4495 DPRINTF("DIRECTION: direc: LOCAL: %d REMOTE: %d\n",Transfer->GetSrcDirection(), Transfer->GetDstDirection() );
4496
4497 // equal direction ...
4498 if ( Transfer->GetDstDirection() == Transfer->GetSrcDirection() )
4499 {
4500 // check the level ...
4501 if ( Transfer->GetDstLevel() < Transfer->GetSrcLevel() )
4502 {
4503 // now we must change the dst direction
4504 if ( Transfer->GetSrcDirection() == edDOWNLOAD )
4505 {
4506 Transfer->SetDstDirection(edUPLOAD);
4507 bdirec = true;
4508 }
4509 else if ( Transfer->GetSrcDirection() == edUPLOAD )
4510 {
4511 Transfer->SetDstDirection(edDOWNLOAD);
4512 bdirec = true;
4513 }
4514 }
4515 else if ( Transfer->GetDstLevel() > Transfer->GetSrcLevel() )
4516 {
4517 if ( Transfer->GetSrcDirection() == edDOWNLOAD )
4518 {
4519 // change direction from download to upload and update the queue state
4520 if ( ChangeDirection(Transfer) )
4521 {
4522 Transfer->SetSrcDirection(edUPLOAD);
4523 bdirec = true;
4524 }
4525 }
4526 else if ( (Transfer->GetSrcDirection() == edUPLOAD) && (Transfer->GetDstDirection() == edUPLOAD) )
4527 {
4528 SendLogInfo( "Warning: remote want to upload a file !", Transfer );
4529 }
4530 else
4531 {
4532 SendLogInfo( "Warning: change direction not supported !", Transfer );
4533 }
4534 }
4535 }
4536 else
4537 {
4538 bdirec = true;
4539 }
4540
4541 if ( bdirec )
4542 {
4543 // now we try to set direction with a slot check (update slots)
4544 if ( SetDirection(Transfer) == false )
4545 {
4546 bdirec = false;
4547 }
4548 }
4549
4550 if ( bdirec == false )
4551 {
4552 SendLogInfo( "Warning no more free slots", Transfer );
4553 Transfer->SetDstDirection(edNONE);
4554 Transfer->SendMaxedOut();
4555 Transfer->Disconnect(true);
4556 }
4557 // check if both modes set correct
4558 else if ( (Transfer->GetSrcDirection() == edNONE) ||
4559 (Transfer->GetDstDirection() == edNONE))
4560 {
4561 DPRINTF("DIRECTION: wrong mode ...\n");
4562 SendLogInfo( "Warning wrong transfer mode", Transfer );
4563 Transfer->SetDstDirection(edNONE);
4564 Transfer->Disconnect(true);
4565 }
4566 else
4567 {
4568 if ( Transfer->GetSrcDirection() == edDOWNLOAD )
4569 {
4570 DPRINTF("DIRECTION: download mode ...\n");
4571
4572 while (1)
4573 {
4574 if ( SetNextFile(Transfer) == false )
4575 {
4576 DPRINTF("DIRECTION: download mode without destination file -> disconnecting!\n");
4577 Transfer->Disconnect(true);
4578 break;
4579 }
4580 else if ( Transfer->GetMedium() == eltCLIENTVERSION )
4581 {
4582 UpdateFileState(Transfer,etfsNONE);
4583 }
4584 else
4585 {
4586 break;
4587 }
4588 }
4589 }
4590 else if ( Transfer->GetSrcDirection() == edUPLOAD )
4591 {
4592 DPRINTF("DIRECTION: we are in upload mode ...\n");
4593 }
4594 }
4595
4596 break;
4597 }
4598
4599 case DC_MESSAGE_CONNECTION_STATE:
4600 {
4601 // connection-state message, generated by the ctransfer-class
4602 remove = true;
4603 CMessageConnectionState *msg = (CMessageConnectionState*)DCMsg;
4604
4605 switch(msg->m_eState)
4606 {
4607 case estDISCONNECTED:
4608 SendLogInfo( "Disconnected from "+Transfer->GetHost(), Transfer );
4609 break;
4610
4611 // case estCONNECTED:
4612 // case estSOCKETERROR:
4613 // case estCONNECTIONTIMEOUT:
4614 default:
4615 remove = false;
4616 break;
4617 }
4618
4619 if ( remove && (Transfer->GetSrcDirection() == edDOWNLOAD) )
4620 {
4621 if ( Transfer->GetMedium() == eltBUFFER )
4622 Transfer->SetStartPosition(0);
4623 UpdateFileState(Transfer,etfsNONE);
4624 }
4625
4626 if ( remove )
4627 {
4628 UpdateWaitTransfer(Transfer,true);
4629
4630 Transfer->SetDone(etsREADY);
4631 }
4632
4633 break;
4634 }
4635
4636 case DC_MESSAGE_TRANSFER:
4637 {
4638 // transfer message, generated by the ctransfer-class
4639 // CMessageTransfer *msg = (CMessageTransfer*)DCMsg;
4640
4641 // filetransfer done
4642 if ( Transfer->GetChunkSize() == Transfer->GetTransfered() )
4643 {
4644 // download ready
4645 if ( Transfer->GetSrcDirection() == edDOWNLOAD )
4646 {
4647 bool b = false;
4648
4649 // set new chunk-end if available
4650 if ( (Transfer->GetMedium() == eltFILE) &&
4651 (Transfer->SupportsChunks() == false) )
4652 {
4653 ulonglong lstart,lend;
4654
4655 // get new chunk end
4656 if ( GetNewChunkEnd( Transfer->GetSrcFilename(), Transfer->GetStartPosition(), Transfer->GetEndPosition(), Transfer->GetStartPosition()+Transfer->GetTransfered(), &lstart, &lend ) )
4657 {
4658 Transfer->SetStartPosition(lstart);
4659 Transfer->SetEndPosition(lend);
4660 Transfer->SetChunkSize(lend-lstart);
4661 Transfer->SetTransfered(0);
4662 // reset stattime
4663 Transfer->SetStartTime(time(0));
4664
4665 b = true;
4666 }
4667
4668 }
4669
4670 // no new chunkend set
4671 if ( b == false )
4672 {
4673 UpdateFileState(Transfer,etfsNONE);
4674
4675 // check if transfer in idle state and set next file
4676 if ( Transfer->IsIdle() )
4677 {
4678 while ( SetNextFile(Transfer) )
4679 {
4680 if ( Transfer->GetMedium() == eltCLIENTVERSION )
4681 {
4682 UpdateFileState(Transfer,etfsNONE);
4683 }
4684 else
4685 {
4686 break;
4687 }
4688 }
4689 }
4690 }
4691 }
4692 else // upload ready
4693 {
4694 // set timeout to save local slots
4695 if ( Transfer->GetDone() != etsIDLE )
4696 {
4697 Transfer->SetStartTime(time(0));
4698 Transfer->SetDone(etsIDLE);
4699 }
4700 }
4701 }
4702
4703 break;
4704 }
4705
4706 case DC_MESSAGE_FILELENGTH:
4707 {
4708 // remote send a filelength
4709 CMessageFileLength * msg = (CMessageFileLength*)DCMsg;
4710
4711 if ( msg->m_nFileLength == 0 )
4712 {
4713 SendLogInfo( "Warning: Filelength is NULL.", Transfer );
4714
4715 if ( Transfer->GetSrcDirection() == edDOWNLOAD )
4716 {
4717 UpdateFileState(Transfer,etfsERROR);
4718 }
4719
4720 Transfer->Disconnect(true);
4721 }
4722 else
4723 {
4724 SendTransferInfo(Transfer);
4725 }
4726
4727 break;
4728 }
4729
4730 case DC_MESSAGE_SENDING:
4731 {
4732 CMessageSending * msg = (CMessageSending*)DCMsg;
4733
4734 if ( msg->m_nLength == 0)
4735 {
4736 SendLogInfo( "Warning: $Sending length is 0", Transfer );
4737 }
4738
4739 SendTransferInfo(Transfer);
4740
4741 break;
4742 }
4743
4744 case DC_MESSAGE_ADCSND:
4745 {
4746 CMessageADCSnd * msg = (CMessageADCSnd*)DCMsg;
4747
4748 if ( msg->m_nSize == 0 )
4749 {
4750 SendLogInfo( "Warning: $ADCSnd size is 0", Transfer );
4751 }
4752
4753 SendTransferInfo(Transfer);
4754
4755 break;
4756 }
4757
4758 case DC_MESSAGE_SEND:
4759 {
4760 // handled by CTransfer, but send message to update GUI
4761 SendTransferInfo(Transfer);
4762 break;
4763 }
4764
4765 case DC_MESSAGE_MAXEDOUT:
4766 {
4767 // no free slots on the remote side
4768 SendLogInfo( "Busy", Transfer );
4769 Transfer->Disconnect(true);
4770 break;
4771 }
4772
4773 case DC_MESSAGE_GETLISTLEN:
4774 {
4775 // remote want the listlen
4776 if ( Transfer->GetSupport().m_bXMLBZList )
4777 Transfer->SendListLen(CFileManager::Instance()->GetShareBufferSize(esbtXMLBZ));
4778 else if ( Transfer->GetSupport().m_bBZList )
4779 Transfer->SendListLen(CFileManager::Instance()->GetShareBufferSize(esbtBZ));
4780 else
4781 Transfer->SendListLen(CFileManager::Instance()->GetShareBufferSize(esbtHE3));
4782 break;
4783 }
4784
4785 case DC_MESSAGE_ERROR:
4786 {
4787 // remote send a error message
4788 CMessageError * msg = (CMessageError*)DCMsg;
4789
4790 SendLogInfo( "Error: " + msg->m_sError, Transfer );
4791
4792 if ( Transfer->GetSrcDirection() == edDOWNLOAD )
4793 {
4794 UpdateFileState(Transfer,etfsERROR);
4795
4796 while ( SetNextFile(Transfer) )
4797 {
4798 if ( Transfer->GetMedium() == eltCLIENTVERSION )
4799 {
4800 UpdateFileState(Transfer,etfsNONE);
4801 }
4802 else
4803 {
4804 break;
4805 }
4806 }
4807 }
4808 break;
4809 }
4810
4811 case DC_MESSAGE_LOCK:
4812 {
4813 CMessageLock * msg = (CMessageLock*)DCMsg;
4814
4815 CConnectionManager::Instance()->SetUserTransferInfo( Transfer->GetHubName(), Transfer->GetHubHost(), Transfer->GetDstNick(), msg );
4816
4817 CString s = "Client: ";
4818
4819 switch(msg->m_eClientVersion)
4820 {
4821 case eucvDCPP:
4822 s += "DC++";
4823 break;
4824 case eucvDCGUI:
4825 s += "Valknut"; // really dclib...
4826 break;
4827 case eucvMICRODC:
4828 s += "microdc";
4829 break;
4830 case eucvSHAKESPEER:
4831 s += "ShakesPeer";
4832 break;
4833 default:
4834 s += "Unknown";
4835 break;
4836 }
4837
4838 if ( msg->m_sVersionString.NotEmpty() )
4839 {
4840 s += " (";
4841 s += msg->m_sVersionString;
4842 s += ')';
4843 }
4844
4845 SendLogInfo( s, Transfer );
4846
4847 break;
4848 }
4849
4850 case DC_MESSAGE_SUPPORTS:
4851 {
4852 CMessageSupports * msg = (CMessageSupports*)DCMsg;
4853
4854 CConnectionManager::Instance()->SetUserTransferInfo( Transfer->GetHubName(), Transfer->GetHubHost(), Transfer->GetDstNick(), msg );
4855
4856 break;
4857 }
4858
4859 case DC_MESSAGE_LOG:
4860 {
4861 SendLogInfo( ((CMessageLog*)DCMsg)->sMessage, Transfer );
4862 break;
4863 }
4864
4865 default:
4866 {
4867 DPRINTF("dctransfer unknown message: %d\n",DCMsg->m_eType);
4868 break;
4869 }
4870 }
4871
4872 delete DCMsg;
4873
4874 TransferCallBackMutex.UnLock();
4875
4876 return 0;
4877 }
4878