00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #if defined(ENABLE_NETWORK)
00013
00014 #include "../stdafx.h"
00015 #include "../rev.h"
00016 #include "../ai/ai.hpp"
00017 #include "../window_func.h"
00018 #include "../gui.h"
00019 #include "../base_media_base.h"
00020 #include "../settings_type.h"
00021 #include "network_content.h"
00022
00023 #include "table/strings.h"
00024
00025 #if defined(WITH_ZLIB)
00026 #include <zlib.h>
00027 #endif
00028
00029 extern bool HasScenario(const ContentInfo *ci, bool md5sum);
00030
00032 ClientNetworkContentSocketHandler _network_content_client;
00033
00035 static bool HasGRFConfig(const ContentInfo *ci, bool md5sum)
00036 {
00037 return FindGRFConfig(BSWAP32(ci->unique_id), md5sum ? FGCM_EXACT : FGCM_ANY, md5sum ? ci->md5sum : NULL) != NULL;
00038 }
00039
00047 typedef bool (*HasProc)(const ContentInfo *ci, bool md5sum);
00048
00049 bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet *p)
00050 {
00051 ContentInfo *ci = new ContentInfo();
00052 ci->type = (ContentType)p->Recv_uint8();
00053 ci->id = (ContentID)p->Recv_uint32();
00054 ci->filesize = p->Recv_uint32();
00055
00056 p->Recv_string(ci->name, lengthof(ci->name));
00057 p->Recv_string(ci->version, lengthof(ci->name));
00058 p->Recv_string(ci->url, lengthof(ci->url));
00059 p->Recv_string(ci->description, lengthof(ci->description), true);
00060
00061 ci->unique_id = p->Recv_uint32();
00062 for (uint j = 0; j < sizeof(ci->md5sum); j++) {
00063 ci->md5sum[j] = p->Recv_uint8();
00064 }
00065
00066 ci->dependency_count = p->Recv_uint8();
00067 ci->dependencies = MallocT<ContentID>(ci->dependency_count);
00068 for (uint i = 0; i < ci->dependency_count; i++) ci->dependencies[i] = (ContentID)p->Recv_uint32();
00069
00070 ci->tag_count = p->Recv_uint8();
00071 ci->tags = MallocT<char[32]>(ci->tag_count);
00072 for (uint i = 0; i < ci->tag_count; i++) p->Recv_string(ci->tags[i], lengthof(*ci->tags));
00073
00074 if (!ci->IsValid()) {
00075 delete ci;
00076 this->Close();
00077 return false;
00078 }
00079
00080
00081 HasProc proc = NULL;
00082 switch (ci->type) {
00083 case CONTENT_TYPE_NEWGRF:
00084 proc = HasGRFConfig;
00085 break;
00086
00087 case CONTENT_TYPE_BASE_GRAPHICS:
00088 proc = BaseGraphics::HasSet;
00089 break;
00090
00091 case CONTENT_TYPE_BASE_MUSIC:
00092 proc = BaseMusic::HasSet;
00093 break;
00094
00095 case CONTENT_TYPE_BASE_SOUNDS:
00096 proc = BaseSounds::HasSet;
00097 break;
00098
00099 case CONTENT_TYPE_AI:
00100 case CONTENT_TYPE_AI_LIBRARY:
00101 proc = AI::HasAI; break;
00102 break;
00103
00104 case CONTENT_TYPE_SCENARIO:
00105 case CONTENT_TYPE_HEIGHTMAP:
00106 proc = HasScenario;
00107 break;
00108
00109 default:
00110 break;
00111 }
00112
00113 if (proc != NULL) {
00114 if (proc(ci, true)) {
00115 ci->state = ContentInfo::ALREADY_HERE;
00116 } else {
00117 ci->state = ContentInfo::UNSELECTED;
00118 if (proc(ci, false)) ci->upgrade = true;
00119 }
00120 } else {
00121 ci->state = ContentInfo::UNSELECTED;
00122 }
00123
00124
00125 if (ci->state == ContentInfo::UNSELECTED && ci->filesize == 0) ci->state = ContentInfo::DOES_NOT_EXIST;
00126
00127
00128 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00129 ContentInfo *ici = *iter;
00130 if (ici->type == ci->type && ici->unique_id == ci->unique_id &&
00131 memcmp(ci->md5sum, ici->md5sum, sizeof(ci->md5sum)) == 0) {
00132
00133 if (StrEmpty(ci->name)) strecpy(ci->name, ici->name, lastof(ci->name));
00134 if (ici->IsSelected()) ci->state = ici->state;
00135
00136
00137
00138
00139
00140
00141
00142 ici->TransferFrom(ci);
00143 delete ci;
00144
00145 this->OnReceiveContentInfo(ici);
00146 return true;
00147 }
00148 }
00149
00150
00151 if (ci->filesize == 0) {
00152 delete ci;
00153 return true;
00154 }
00155
00156 *this->infos.Append() = ci;
00157
00158
00159 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00160 this->CheckDependencyState(*iter);
00161 }
00162
00163 this->OnReceiveContentInfo(ci);
00164
00165 return true;
00166 }
00167
00172 void ClientNetworkContentSocketHandler::RequestContentList(ContentType type)
00173 {
00174 if (type == CONTENT_TYPE_END) {
00175 this->RequestContentList(CONTENT_TYPE_BASE_GRAPHICS);
00176 this->RequestContentList(CONTENT_TYPE_BASE_MUSIC);
00177 this->RequestContentList(CONTENT_TYPE_BASE_SOUNDS);
00178 this->RequestContentList(CONTENT_TYPE_SCENARIO);
00179 this->RequestContentList(CONTENT_TYPE_HEIGHTMAP);
00180 #ifdef ENABLE_AI
00181 this->RequestContentList(CONTENT_TYPE_AI);
00182 this->RequestContentList(CONTENT_TYPE_AI_LIBRARY);
00183 #endif
00184 this->RequestContentList(CONTENT_TYPE_NEWGRF);
00185 return;
00186 }
00187
00188 this->Connect();
00189
00190 Packet *p = new Packet(PACKET_CONTENT_CLIENT_INFO_LIST);
00191 p->Send_uint8 ((byte)type);
00192 p->Send_uint32(_openttd_newgrf_version);
00193
00194 this->SendPacket(p);
00195 }
00196
00202 void ClientNetworkContentSocketHandler::RequestContentList(uint count, const ContentID *content_ids)
00203 {
00204 this->Connect();
00205
00206 while (count > 0) {
00207
00208
00209
00210
00211
00212 uint p_count = min(count, (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(byte) - sizeof(uint16)) / sizeof(uint32));
00213
00214 Packet *p = new Packet(PACKET_CONTENT_CLIENT_INFO_ID);
00215 p->Send_uint16(p_count);
00216
00217 for (uint i = 0; i < p_count; i++) {
00218 p->Send_uint32(content_ids[i]);
00219 }
00220
00221 this->SendPacket(p);
00222 count -= p_count;
00223 content_ids += p_count;
00224 }
00225 }
00226
00232 void ClientNetworkContentSocketHandler::RequestContentList(ContentVector *cv, bool send_md5sum)
00233 {
00234 if (cv == NULL) return;
00235
00236 this->Connect();
00237
00238
00239 assert(cv->Length() < 255);
00240 assert(cv->Length() < (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint8)) / (send_md5sum ? 20 : sizeof(uint32)));
00241
00242 Packet *p = new Packet(send_md5sum ? PACKET_CONTENT_CLIENT_INFO_EXTID_MD5 : PACKET_CONTENT_CLIENT_INFO_EXTID);
00243 p->Send_uint8(cv->Length());
00244
00245 for (ContentIterator iter = cv->Begin(); iter != cv->End(); iter++) {
00246 const ContentInfo *ci = *iter;
00247 p->Send_uint8((byte)ci->type);
00248 p->Send_uint32(ci->unique_id);
00249 if (!send_md5sum) continue;
00250
00251 for (uint j = 0; j < sizeof(ci->md5sum); j++) {
00252 p->Send_uint8(ci->md5sum[j]);
00253 }
00254 }
00255
00256 this->SendPacket(p);
00257
00258 for (ContentIterator iter = cv->Begin(); iter != cv->End(); iter++) {
00259 ContentInfo *ci = *iter;
00260 bool found = false;
00261 for (ContentIterator iter2 = this->infos.Begin(); iter2 != this->infos.End(); iter2++) {
00262 ContentInfo *ci2 = *iter2;
00263 if (ci->type == ci2->type && ci->unique_id == ci2->unique_id &&
00264 (!send_md5sum || memcmp(ci->md5sum, ci2->md5sum, sizeof(ci->md5sum)) == 0)) {
00265 found = true;
00266 break;
00267 }
00268 }
00269 if (!found) {
00270 *this->infos.Append() = ci;
00271 } else {
00272 delete ci;
00273 }
00274 }
00275 }
00276
00283 void ClientNetworkContentSocketHandler::DownloadSelectedContent(uint &files, uint &bytes, bool fallback)
00284 {
00285 bytes = 0;
00286
00287 ContentIDList content;
00288 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00289 const ContentInfo *ci = *iter;
00290 if (!ci->IsSelected() || ci->state == ContentInfo::ALREADY_HERE) continue;
00291
00292 *content.Append() = ci->id;
00293 bytes += ci->filesize;
00294 }
00295
00296 files = content.Length();
00297
00298
00299 if (files == 0) return;
00300
00301 if (_settings_client.network.no_http_content_downloads || fallback) {
00302 this->DownloadSelectedContentFallback(content);
00303 } else {
00304 this->DownloadSelectedContentHTTP(content);
00305 }
00306 }
00307
00312 void ClientNetworkContentSocketHandler::DownloadSelectedContentHTTP(const ContentIDList &content)
00313 {
00314 uint count = content.Length();
00315
00316
00317
00318
00319
00320 uint bytes = (10 + 1) * count + 1;
00321 char *content_request = MallocT<char>(bytes);
00322 const char *lastof = content_request + bytes - 1;
00323
00324 char *p = content_request;
00325 for (const ContentID *id = content.Begin(); id != content.End(); id++) {
00326 p += seprintf(p, lastof, "%d\n", *id);
00327 }
00328
00329 this->http_response_index = -1;
00330
00331 NetworkAddress address(NETWORK_CONTENT_MIRROR_HOST, NETWORK_CONTENT_MIRROR_PORT);
00332 new NetworkHTTPContentConnecter(address, this, NETWORK_CONTENT_MIRROR_URL, content_request);
00333
00334 }
00335
00340 void ClientNetworkContentSocketHandler::DownloadSelectedContentFallback(const ContentIDList &content)
00341 {
00342 uint count = content.Length();
00343 const ContentID *content_ids = content.Begin();
00344 this->Connect();
00345
00346 while (count > 0) {
00347
00348
00349
00350
00351 uint p_count = min(count, (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint16)) / sizeof(uint32));
00352
00353 Packet *p = new Packet(PACKET_CONTENT_CLIENT_CONTENT);
00354 p->Send_uint16(p_count);
00355
00356 for (uint i = 0; i < p_count; i++) {
00357 p->Send_uint32(content_ids[i]);
00358 }
00359
00360 this->SendPacket(p);
00361 count -= p_count;
00362 content_ids += p_count;
00363 }
00364 }
00365
00373 static char *GetFullFilename(const ContentInfo *ci, bool compressed)
00374 {
00375 Subdirectory dir;
00376 switch (ci->type) {
00377 default: return NULL;
00378 case CONTENT_TYPE_BASE_GRAPHICS: dir = DATA_DIR; break;
00379 case CONTENT_TYPE_BASE_MUSIC: dir = GM_DIR; break;
00380 case CONTENT_TYPE_BASE_SOUNDS: dir = DATA_DIR; break;
00381 case CONTENT_TYPE_NEWGRF: dir = DATA_DIR; break;
00382 case CONTENT_TYPE_AI: dir = AI_DIR; break;
00383 case CONTENT_TYPE_AI_LIBRARY: dir = AI_LIBRARY_DIR; break;
00384 case CONTENT_TYPE_SCENARIO: dir = SCENARIO_DIR; break;
00385 case CONTENT_TYPE_HEIGHTMAP: dir = HEIGHTMAP_DIR; break;
00386 }
00387
00388 static char buf[MAX_PATH];
00389 FioGetFullPath(buf, lengthof(buf), SP_AUTODOWNLOAD_DIR, dir, ci->filename);
00390 strecat(buf, compressed ? ".tar.gz" : ".tar", lastof(buf));
00391
00392 return buf;
00393 }
00394
00400 static bool GunzipFile(const ContentInfo *ci)
00401 {
00402 #if defined(WITH_ZLIB)
00403 bool ret = true;
00404 FILE *ftmp = fopen(GetFullFilename(ci, true), "rb");
00405 gzFile fin = gzdopen(fileno(ftmp), "rb");
00406 FILE *fout = fopen(GetFullFilename(ci, false), "wb");
00407
00408 if (fin == NULL || fout == NULL) {
00409 ret = false;
00410 } else {
00411 byte buff[8192];
00412 for (;;) {
00413 int read = gzread(fin, buff, sizeof(buff));
00414 if (read == 0) {
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427 int errnum;
00428 gzerror(fin, &errnum);
00429 if (errnum != 0 && errnum != Z_STREAM_END) ret = false;
00430 break;
00431 }
00432 if (read < 0 || (size_t)read != fwrite(buff, 1, read, fout)) {
00433
00434 ret = false;
00435 break;
00436 }
00437
00438
00439 }
00440 }
00441
00442 if (fin != NULL) {
00443
00444 gzclose(fin);
00445 } else if (ftmp != NULL) {
00446
00447
00448 fclose(ftmp);
00449 }
00450 if (fout != NULL) fclose(fout);
00451
00452 return ret;
00453 #else
00454 NOT_REACHED();
00455 #endif
00456 }
00457
00458 bool ClientNetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet *p)
00459 {
00460 if (this->curFile == NULL) {
00461 delete this->curInfo;
00462
00463 this->curInfo = new ContentInfo;
00464 this->curInfo->type = (ContentType)p->Recv_uint8();
00465 this->curInfo->id = (ContentID)p->Recv_uint32();
00466 this->curInfo->filesize = p->Recv_uint32();
00467 p->Recv_string(this->curInfo->filename, lengthof(this->curInfo->filename));
00468
00469 if (!this->BeforeDownload()) {
00470 this->Close();
00471 return false;
00472 }
00473 } else {
00474
00475 size_t toRead = (size_t)(p->size - p->pos);
00476 if (fwrite(p->buffer + p->pos, 1, toRead, this->curFile) != toRead) {
00477 DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
00478 ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, WL_ERROR);
00479 this->Close();
00480 fclose(this->curFile);
00481 this->curFile = NULL;
00482
00483 return false;
00484 }
00485
00486 this->OnDownloadProgress(this->curInfo, (int)toRead);
00487
00488 if (toRead == 0) this->AfterDownload();
00489 }
00490
00491 return true;
00492 }
00493
00498 bool ClientNetworkContentSocketHandler::BeforeDownload()
00499 {
00500 if (!this->curInfo->IsValid()) {
00501 delete this->curInfo;
00502 this->curInfo = NULL;
00503 return false;
00504 }
00505
00506 if (this->curInfo->filesize != 0) {
00507
00508 const char *filename = GetFullFilename(this->curInfo, true);
00509 if (filename == NULL || (this->curFile = fopen(filename, "wb")) == NULL) {
00510
00511 DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
00512 ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, WL_ERROR);
00513 return false;
00514 }
00515 }
00516 return true;
00517 }
00518
00523 void ClientNetworkContentSocketHandler::AfterDownload()
00524 {
00525
00526
00527 fclose(this->curFile);
00528 this->curFile = NULL;
00529
00530 if (GunzipFile(this->curInfo)) {
00531 unlink(GetFullFilename(this->curInfo, true));
00532
00533 TarScanner ts;
00534 ts.AddFile(GetFullFilename(this->curInfo, false), 0);
00535
00536 if (this->curInfo->type == CONTENT_TYPE_BASE_MUSIC) {
00537
00538 ExtractTar(GetFullFilename(this->curInfo, false));
00539 unlink(GetFullFilename(this->curInfo, false));
00540 }
00541
00542 this->OnDownloadComplete(this->curInfo->id);
00543 } else {
00544 ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_EXTRACT, INVALID_STRING_ID, WL_ERROR);
00545 }
00546 }
00547
00548
00549 void ClientNetworkContentSocketHandler::OnFailure()
00550 {
00551
00552 uint files, bytes;
00553 this->DownloadSelectedContent(files, bytes, true);
00554
00555 this->http_response.Reset();
00556 this->http_response_index = -2;
00557
00558 if (this->curFile != NULL) {
00559
00560 long size = ftell(this->curFile);
00561 if (size > 0) this->OnDownloadProgress(this->curInfo, (int)-size);
00562
00563 fclose(this->curFile);
00564 this->curFile = NULL;
00565 }
00566 }
00567
00568 void ClientNetworkContentSocketHandler::OnReceiveData(const char *data, size_t length)
00569 {
00570 assert(data == NULL || length != 0);
00571
00572
00573 if (this->http_response_index == -2) return;
00574
00575 if (this->http_response_index == -1) {
00576 if (data != NULL) {
00577
00578 memcpy(this->http_response.Append((uint)length), data, length);
00579 return;
00580 } else {
00581
00582 *this->http_response.Append() = '\0';
00583
00584
00585 this->http_response_index = 0;
00586 }
00587 }
00588
00589 if (data != NULL) {
00590
00591 if (fwrite(data, 1, length, this->curFile) != length) {
00592
00593 this->OnFailure();
00594 } else {
00595
00596 this->OnDownloadProgress(this->curInfo, (int)length);
00597 }
00598
00599 return;
00600 }
00601
00602 if (this->curFile != NULL) {
00603
00604 this->AfterDownload();
00605 }
00606
00607 if ((uint)this->http_response_index >= this->http_response.Length()) {
00608
00609
00610
00611 this->OnFailure();
00612 return;
00613 }
00614
00615 delete this->curInfo;
00616
00617 this->curInfo = new ContentInfo;
00618
00620 #define check_not_null(p) { if ((p) == NULL) { this->OnFailure(); return; } }
00621
00622 #define check_and_terminate(p) { check_not_null(p); *(p) = '\0'; }
00623
00624 for (;;) {
00625 char *str = this->http_response.Begin() + this->http_response_index;
00626 char *p = strchr(str, '\n');
00627 check_and_terminate(p);
00628
00629
00630 this->http_response_index += (int)strlen(str) + 1;
00631
00632
00633 p = strchr(str, ',');
00634 check_and_terminate(p);
00635 this->curInfo->id = (ContentID)atoi(str);
00636
00637
00638 str = p + 1;
00639 p = strchr(str, ',');
00640 check_and_terminate(p);
00641 this->curInfo->type = (ContentType)atoi(str);
00642
00643
00644 str = p + 1;
00645 p = strchr(str, ',');
00646 check_and_terminate(p);
00647 this->curInfo->filesize = atoi(str);
00648
00649
00650 str = p + 1;
00651
00652 if (strncmp(str, "ottd", 4) == 0) {
00653 if ((uint)this->http_response_index >= this->http_response.Length()) {
00654
00655 this->OnFailure();
00656 return;
00657 }
00658 continue;
00659 }
00660
00661 p = strrchr(str, '/');
00662 check_not_null(p);
00663 p++;
00664
00665 char tmp[MAX_PATH];
00666 if (strecpy(tmp, p, lastof(tmp)) == lastof(tmp)) {
00667 this->OnFailure();
00668 return;
00669 }
00670
00671 for (uint i = 0; i < 2; i++) {
00672 p = strrchr(tmp, '.');
00673 check_and_terminate(p);
00674 }
00675
00676
00677 strecpy(this->curInfo->filename, tmp, lastof(this->curInfo->filename));
00678
00679
00680 if (!this->BeforeDownload()) {
00681 this->OnFailure();
00682 return;
00683 }
00684
00685 NetworkHTTPSocketHandler::Connect(str, this);
00686 return;
00687 }
00688
00689 #undef check
00690 #undef check_and_terminate
00691 }
00692
00696 ClientNetworkContentSocketHandler::ClientNetworkContentSocketHandler() :
00697 NetworkContentSocketHandler(),
00698 http_response_index(-2),
00699 curFile(NULL),
00700 curInfo(NULL),
00701 isConnecting(false)
00702 {
00703 }
00704
00706 ClientNetworkContentSocketHandler::~ClientNetworkContentSocketHandler()
00707 {
00708 delete this->curInfo;
00709 if (this->curFile != NULL) fclose(this->curFile);
00710
00711 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) delete *iter;
00712 }
00713
00715 class NetworkContentConnecter : TCPConnecter {
00716 public:
00721 NetworkContentConnecter(const NetworkAddress &address) : TCPConnecter(address) {}
00722
00723 virtual void OnFailure()
00724 {
00725 _network_content_client.isConnecting = false;
00726 _network_content_client.OnConnect(false);
00727 }
00728
00729 virtual void OnConnect(SOCKET s)
00730 {
00731 assert(_network_content_client.sock == INVALID_SOCKET);
00732 _network_content_client.isConnecting = false;
00733 _network_content_client.sock = s;
00734 _network_content_client.Reopen();
00735 _network_content_client.OnConnect(true);
00736 }
00737 };
00738
00742 void ClientNetworkContentSocketHandler::Connect()
00743 {
00744 this->lastActivity = _realtime_tick;
00745
00746 if (this->sock != INVALID_SOCKET || this->isConnecting) return;
00747 this->isConnecting = true;
00748 new NetworkContentConnecter(NetworkAddress(NETWORK_CONTENT_SERVER_HOST, NETWORK_CONTENT_SERVER_PORT, AF_UNSPEC));
00749 }
00750
00754 void ClientNetworkContentSocketHandler::Close()
00755 {
00756 if (this->sock == INVALID_SOCKET) return;
00757 NetworkContentSocketHandler::Close();
00758
00759 this->OnDisconnect();
00760 }
00761
00766 void ClientNetworkContentSocketHandler::SendReceive()
00767 {
00768 if (this->sock == INVALID_SOCKET || this->isConnecting) return;
00769
00770 if (this->lastActivity + IDLE_TIMEOUT < _realtime_tick) {
00771 this->Close();
00772 return;
00773 }
00774
00775 if (this->CanSendReceive()) {
00776 this->ReceivePackets();
00777 this->lastActivity = _realtime_tick;
00778 }
00779
00780 this->SendPackets();
00781 }
00782
00787 void ClientNetworkContentSocketHandler::DownloadContentInfo(ContentID cid)
00788 {
00789
00790 if (this->requested.Contains(cid)) return;
00791
00792 *this->requested.Append() = cid;
00793 assert(this->requested.Contains(cid));
00794 this->RequestContentList(1, &cid);
00795 }
00796
00802 ContentInfo *ClientNetworkContentSocketHandler::GetContent(ContentID cid)
00803 {
00804 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00805 ContentInfo *ci = *iter;
00806 if (ci->id == cid) return ci;
00807 }
00808 return NULL;
00809 }
00810
00811
00816 void ClientNetworkContentSocketHandler::Select(ContentID cid)
00817 {
00818 ContentInfo *ci = this->GetContent(cid);
00819 if (ci == NULL || ci->state != ContentInfo::UNSELECTED) return;
00820
00821 ci->state = ContentInfo::SELECTED;
00822 this->CheckDependencyState(ci);
00823 }
00824
00829 void ClientNetworkContentSocketHandler::Unselect(ContentID cid)
00830 {
00831 ContentInfo *ci = this->GetContent(cid);
00832 if (ci == NULL || !ci->IsSelected()) return;
00833
00834 ci->state = ContentInfo::UNSELECTED;
00835 this->CheckDependencyState(ci);
00836 }
00837
00839 void ClientNetworkContentSocketHandler::SelectAll()
00840 {
00841 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00842 ContentInfo *ci = *iter;
00843 if (ci->state == ContentInfo::UNSELECTED) {
00844 ci->state = ContentInfo::SELECTED;
00845 this->CheckDependencyState(ci);
00846 }
00847 }
00848 }
00849
00851 void ClientNetworkContentSocketHandler::SelectUpgrade()
00852 {
00853 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00854 ContentInfo *ci = *iter;
00855 if (ci->state == ContentInfo::UNSELECTED && ci->upgrade) {
00856 ci->state = ContentInfo::SELECTED;
00857 this->CheckDependencyState(ci);
00858 }
00859 }
00860 }
00861
00863 void ClientNetworkContentSocketHandler::UnselectAll()
00864 {
00865 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00866 ContentInfo *ci = *iter;
00867 if (ci->IsSelected() && ci->state != ContentInfo::ALREADY_HERE) ci->state = ContentInfo::UNSELECTED;
00868 }
00869 }
00870
00872 void ClientNetworkContentSocketHandler::ToggleSelectedState(const ContentInfo *ci)
00873 {
00874 switch (ci->state) {
00875 case ContentInfo::SELECTED:
00876 case ContentInfo::AUTOSELECTED:
00877 this->Unselect(ci->id);
00878 break;
00879
00880 case ContentInfo::UNSELECTED:
00881 this->Select(ci->id);
00882 break;
00883
00884 default:
00885 break;
00886 }
00887 }
00888
00894 void ClientNetworkContentSocketHandler::ReverseLookupDependency(ConstContentVector &parents, const ContentInfo *child) const
00895 {
00896 for (ConstContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00897 const ContentInfo *ci = *iter;
00898 if (ci == child) continue;
00899
00900 for (uint i = 0; i < ci->dependency_count; i++) {
00901 if (ci->dependencies[i] == child->id) {
00902 *parents.Append() = ci;
00903 break;
00904 }
00905 }
00906 }
00907 }
00908
00914 void ClientNetworkContentSocketHandler::ReverseLookupTreeDependency(ConstContentVector &tree, const ContentInfo *child) const
00915 {
00916 *tree.Append() = child;
00917
00918
00919
00920
00921
00922 for (uint i = 0; i < tree.Length(); i++) {
00923 ConstContentVector parents;
00924 this->ReverseLookupDependency(parents, tree[i]);
00925
00926 for (ConstContentIterator piter = parents.Begin(); piter != parents.End(); piter++) {
00927 tree.Include(*piter);
00928 }
00929 }
00930 }
00931
00936 void ClientNetworkContentSocketHandler::CheckDependencyState(ContentInfo *ci)
00937 {
00938 if (ci->IsSelected() || ci->state == ContentInfo::ALREADY_HERE) {
00939
00940
00941
00942 for (uint i = 0; i < ci->dependency_count; i++) {
00943 ContentInfo *c = this->GetContent(ci->dependencies[i]);
00944 if (c == NULL) {
00945 this->DownloadContentInfo(ci->dependencies[i]);
00946 } else if (c->state == ContentInfo::UNSELECTED) {
00947 c->state = ContentInfo::AUTOSELECTED;
00948 this->CheckDependencyState(c);
00949 }
00950 }
00951 return;
00952 }
00953
00954 if (ci->state != ContentInfo::UNSELECTED) return;
00955
00956
00957
00958
00959
00960 ConstContentVector parents;
00961 this->ReverseLookupDependency(parents, ci);
00962 for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
00963 const ContentInfo *c = *iter;
00964 if (!c->IsSelected()) continue;
00965
00966 this->Unselect(c->id);
00967 }
00968
00969 for (uint i = 0; i < ci->dependency_count; i++) {
00970 const ContentInfo *c = this->GetContent(ci->dependencies[i]);
00971 if (c == NULL) {
00972 DownloadContentInfo(ci->dependencies[i]);
00973 continue;
00974 }
00975 if (c->state != ContentInfo::AUTOSELECTED) continue;
00976
00977
00978 parents.Clear();
00979 this->ReverseLookupDependency(parents, c);
00980
00981
00982 int sel_count = 0;
00983 bool force_selection = false;
00984 for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
00985 if ((*iter)->IsSelected()) sel_count++;
00986 if ((*iter)->state == ContentInfo::SELECTED) force_selection = true;
00987 }
00988 if (sel_count == 0) {
00989
00990 this->Unselect(c->id);
00991 continue;
00992 }
00993
00994 if (force_selection) continue;
00995
00996
00997 parents.Clear();
00998 this->ReverseLookupTreeDependency(parents, c);
00999
01000
01001 for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
01002 if ((*iter)->state != ContentInfo::SELECTED) continue;
01003
01004 force_selection = true;
01005 break;
01006 }
01007
01008
01009 if (force_selection) continue;
01010
01011
01012
01013
01014
01015 for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
01016 const ContentInfo *c = *iter;
01017 if (c->state == ContentInfo::AUTOSELECTED) this->Unselect(c->id);
01018 }
01019 for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
01020 this->CheckDependencyState(this->GetContent((*iter)->id));
01021 }
01022 }
01023 }
01024
01026 void ClientNetworkContentSocketHandler::Clear()
01027 {
01028 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) delete *iter;
01029
01030 this->infos.Clear();
01031 this->requested.Clear();
01032 }
01033
01034
01035
01036 void ClientNetworkContentSocketHandler::OnConnect(bool success)
01037 {
01038 for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); ) {
01039 ContentCallback *cb = *iter;
01040 cb->OnConnect(success);
01041 if (iter != this->callbacks.End() && *iter == cb) iter++;
01042 }
01043 }
01044
01045 void ClientNetworkContentSocketHandler::OnDisconnect()
01046 {
01047 for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); ) {
01048 ContentCallback *cb = *iter;
01049 cb->OnDisconnect();
01050 if (iter != this->callbacks.End() && *iter == cb) iter++;
01051 }
01052 }
01053
01054 void ClientNetworkContentSocketHandler::OnReceiveContentInfo(const ContentInfo *ci)
01055 {
01056 for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); ) {
01057 ContentCallback *cb = *iter;
01058 cb->OnReceiveContentInfo(ci);
01059 if (iter != this->callbacks.End() && *iter == cb) iter++;
01060 }
01061 }
01062
01063 void ClientNetworkContentSocketHandler::OnDownloadProgress(const ContentInfo *ci, int bytes)
01064 {
01065 for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); ) {
01066 ContentCallback *cb = *iter;
01067 cb->OnDownloadProgress(ci, bytes);
01068 if (iter != this->callbacks.End() && *iter == cb) iter++;
01069 }
01070 }
01071
01072 void ClientNetworkContentSocketHandler::OnDownloadComplete(ContentID cid)
01073 {
01074 ContentInfo *ci = this->GetContent(cid);
01075 if (ci != NULL) {
01076 ci->state = ContentInfo::ALREADY_HERE;
01077 }
01078
01079 for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); ) {
01080 ContentCallback *cb = *iter;
01081 cb->OnDownloadComplete(cid);
01082 if (iter != this->callbacks.End() && *iter == cb) iter++;
01083 }
01084 }
01085
01086 #endif