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