network_content.cpp

Go to the documentation of this file.
00001 /* $Id: network_content.cpp 15299 2009-01-31 20:16:06Z smatz $ */
00002 
00005 #if defined(ENABLE_NETWORK)
00006 
00007 #include "../stdafx.h"
00008 #include "../rev.h"
00009 #include "../fileio_func.h"
00010 #include "../string_func.h"
00011 #include "../ai/ai.hpp"
00012 #include "../window_func.h"
00013 #include "../gui.h"
00014 #include "../variables.h"
00015 #include "network_content.h"
00016 
00017 #include "table/strings.h"
00018 
00019 #if defined(WITH_ZLIB)
00020 #include <zlib.h>
00021 #endif
00022 
00023 extern bool TarListAddFile(const char *filename);
00024 extern bool HasGraphicsSet(const ContentInfo *ci, bool md5sum);
00025 ClientNetworkContentSocketHandler _network_content_client;
00026 
00028 static bool HasGRFConfig(const ContentInfo *ci, bool md5sum)
00029 {
00030   return FindGRFConfig(BSWAP32(ci->unique_id), md5sum ? ci->md5sum : NULL) != NULL;
00031 }
00032 
00040 typedef bool (*HasProc)(const ContentInfo *ci, bool md5sum);
00041 
00042 DEF_CONTENT_RECEIVE_COMMAND(Client, PACKET_CONTENT_SERVER_INFO)
00043 {
00044   ContentInfo *ci = new ContentInfo();
00045   ci->type     = (ContentType)p->Recv_uint8();
00046   ci->id       = (ContentID)p->Recv_uint32();
00047   ci->filesize = p->Recv_uint32();
00048 
00049   p->Recv_string(ci->name, lengthof(ci->name));
00050   p->Recv_string(ci->version, lengthof(ci->name));
00051   p->Recv_string(ci->url, lengthof(ci->url));
00052   p->Recv_string(ci->description, lengthof(ci->description),  true);
00053 
00054   ci->unique_id = p->Recv_uint32();
00055   for (uint j = 0; j < sizeof(ci->md5sum); j++) {
00056     ci->md5sum[j] = p->Recv_uint8();
00057   }
00058 
00059   ci->dependency_count = p->Recv_uint8();
00060   ci->dependencies = MallocT<ContentID>(ci->dependency_count);
00061   for (uint i = 0; i < ci->dependency_count; i++) ci->dependencies[i] = (ContentID)p->Recv_uint32();
00062 
00063   ci->tag_count = p->Recv_uint8();
00064   ci->tags = MallocT<char[32]>(ci->tag_count);
00065   for (uint i = 0; i < ci->tag_count; i++) p->Recv_string(ci->tags[i], lengthof(*ci->tags));
00066 
00067   if (!ci->IsValid()) {
00068     delete ci;
00069     this->Close();
00070     return false;
00071   }
00072 
00073   /* Find the appropriate check function */
00074   HasProc proc = NULL;
00075   switch (ci->type) {
00076     case CONTENT_TYPE_NEWGRF:
00077       proc = HasGRFConfig;
00078       break;
00079 
00080     case CONTENT_TYPE_BASE_GRAPHICS:
00081       proc = HasGraphicsSet;
00082       break;
00083 
00084     case CONTENT_TYPE_AI:
00085     case CONTENT_TYPE_AI_LIBRARY:
00086       proc = AI::HasAI; break;
00087       break;
00088 
00089     default:
00090       break;
00091   }
00092 
00093   if (proc != NULL) {
00094     if (proc(ci, true)) {
00095       ci->state = ContentInfo::ALREADY_HERE;
00096     } else {
00097       ci->state = ContentInfo::UNSELECTED;
00098       if (proc(ci, false)) ci->upgrade = true;
00099     }
00100   } else {
00101     ci->state = ContentInfo::UNSELECTED;
00102   }
00103 
00104   /* Something we don't have and has filesize 0 does not exist in te system */
00105   if (ci->state == ContentInfo::UNSELECTED && ci->filesize == 0) ci->state = ContentInfo::DOES_NOT_EXIST;
00106 
00107   /* Do we already have a stub for this? */
00108   for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00109     ContentInfo *ici = *iter;
00110     if (ici->type == ci->type && ici->unique_id == ci->unique_id &&
00111         memcmp(ci->md5sum, ici->md5sum, sizeof(ci->md5sum)) == 0) {
00112       /* Preserve the name if possible */
00113       if (StrEmpty(ci->name)) strecpy(ci->name, ici->name, lastof(ci->name));
00114       if (ici->IsSelected()) ci->state = ici->state;
00115 
00116       delete ici;
00117       *iter = ci;
00118 
00119       this->OnReceiveContentInfo(ci);
00120       return true;
00121     }
00122   }
00123 
00124   /* Missing content info? Don't list it */
00125   if (ci->filesize == 0) {
00126     delete ci;
00127     return true;
00128   }
00129 
00130   *this->infos.Append() = ci;
00131 
00132   /* Incoming data means that we might need to reconsider dependencies */
00133   for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00134     this->CheckDependencyState(*iter);
00135   }
00136 
00137   this->OnReceiveContentInfo(ci);
00138 
00139   return true;
00140 }
00141 
00142 void ClientNetworkContentSocketHandler::RequestContentList(ContentType type)
00143 {
00144   if (type == CONTENT_TYPE_END) {
00145     this->RequestContentList(CONTENT_TYPE_BASE_GRAPHICS);
00146     this->RequestContentList(CONTENT_TYPE_AI);
00147     this->RequestContentList(CONTENT_TYPE_NEWGRF);
00148     this->RequestContentList(CONTENT_TYPE_AI_LIBRARY);
00149     return;
00150   }
00151 
00152   this->Connect();
00153 
00154   Packet *p = new Packet(PACKET_CONTENT_CLIENT_INFO_LIST);
00155   p->Send_uint8 ((byte)type);
00156   p->Send_uint32(_openttd_newgrf_version);
00157 
00158   this->Send_Packet(p);
00159 }
00160 
00161 void ClientNetworkContentSocketHandler::RequestContentList(uint count, const ContentID *content_ids)
00162 {
00163   this->Connect();
00164 
00165   while (count > 0) {
00166     /* We can "only" send a limited number of IDs in a single packet.
00167      * A packet begins with the packet size and a byte for the type.
00168      * Then this packet adds a byte for the content type and a uint16
00169      * for the count in this packet. The rest of the packet can be
00170      * used for the IDs. */
00171     uint p_count = min(count, (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(byte) - sizeof(uint16)) / sizeof(uint32));
00172 
00173     Packet *p = new Packet(PACKET_CONTENT_CLIENT_INFO_ID);
00174     p->Send_uint16(p_count);
00175 
00176     for (uint i = 0; i < p_count; i++) {
00177       p->Send_uint32(content_ids[i]);
00178     }
00179 
00180     this->Send_Packet(p);
00181     count -= p_count;
00182     content_ids += count;
00183   }
00184 }
00185 
00186 void ClientNetworkContentSocketHandler::RequestContentList(ContentVector *cv, bool send_md5sum)
00187 {
00188   if (cv == NULL) return;
00189 
00190   this->Connect();
00191 
00192   /* 20 is sizeof(uint32) + sizeof(md5sum (byte[16])) */
00193   assert(cv->Length() < 255);
00194   assert(cv->Length() < (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint8)) / (send_md5sum ? 20 : sizeof(uint32)));
00195 
00196   Packet *p = new Packet(send_md5sum ? PACKET_CONTENT_CLIENT_INFO_EXTID_MD5 : PACKET_CONTENT_CLIENT_INFO_EXTID);
00197   p->Send_uint8(cv->Length());
00198 
00199   for (ContentIterator iter = cv->Begin(); iter != cv->End(); iter++) {
00200     const ContentInfo *ci = *iter;
00201     p->Send_uint8((byte)ci->type);
00202     p->Send_uint32(ci->unique_id);
00203     if (!send_md5sum) continue;
00204 
00205     for (uint j = 0; j < sizeof(ci->md5sum); j++) {
00206       p->Send_uint8(ci->md5sum[j]);
00207     }
00208   }
00209 
00210   this->Send_Packet(p);
00211 
00212   for (ContentIterator iter = cv->Begin(); iter != cv->End(); iter++) {
00213     ContentInfo *ci = *iter;
00214     bool found = false;
00215     for (ContentIterator iter2 = this->infos.Begin(); iter2 != this->infos.End(); iter2++) {
00216       ContentInfo *ci2 = *iter2;
00217       if (ci->type == ci2->type && ci->unique_id == ci2->unique_id &&
00218           (!send_md5sum || memcmp(ci->md5sum, ci2->md5sum, sizeof(ci->md5sum)) == 0)) {
00219         found = true;
00220         break;
00221       }
00222     }
00223     if (!found) {
00224       *this->infos.Append() = ci;
00225     } else {
00226       delete ci;
00227     }
00228   }
00229 }
00230 
00231 void ClientNetworkContentSocketHandler::DownloadSelectedContent(uint &files, uint &bytes)
00232 {
00233   files = 0;
00234   bytes = 0;
00235 
00237   ContentID *ids = MallocT<ContentID>(infos.Length());
00238   for (ContentIterator iter = infos.Begin(); iter != infos.End(); iter++) {
00239     const ContentInfo *ci = *iter;
00240     if (!ci->IsSelected()) continue;
00241 
00242     ids[files++] = ci->id;
00243     bytes += ci->filesize;
00244   }
00245 
00246   uint count = files;
00247   ContentID *content_ids = ids;
00248   this->Connect();
00249 
00250   while (count > 0) {
00251     /* We can "only" send a limited number of IDs in a single packet.
00252     * A packet begins with the packet size and a byte for the type.
00253     * Then this packet adds a uint16 for the count in this packet.
00254     * The rest of the packet can be used for the IDs. */
00255     uint p_count = min(count, (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint16)) / sizeof(uint32));
00256 
00257     Packet *p = new Packet(PACKET_CONTENT_CLIENT_CONTENT);
00258     p->Send_uint16(p_count);
00259 
00260     for (uint i = 0; i < p_count; i++) {
00261       p->Send_uint32(content_ids[i]);
00262     }
00263 
00264     this->Send_Packet(p);
00265     count -= p_count;
00266     content_ids += count;
00267   }
00268 
00269   free(ids);
00270 }
00271 
00279 static char *GetFullFilename(const ContentInfo *ci, bool compressed)
00280 {
00281   Subdirectory dir;
00282   switch (ci->type) {
00283     default: return NULL;
00284     case CONTENT_TYPE_BASE_GRAPHICS: dir = DATA_DIR;       break;
00285     case CONTENT_TYPE_NEWGRF:        dir = DATA_DIR;       break;
00286     case CONTENT_TYPE_AI:            dir = AI_DIR;         break;
00287     case CONTENT_TYPE_AI_LIBRARY:    dir = AI_LIBRARY_DIR; break;
00288     case CONTENT_TYPE_SCENARIO:      dir = SCENARIO_DIR;   break;
00289     case CONTENT_TYPE_HEIGHTMAP:     dir = HEIGHTMAP_DIR;  break;
00290   }
00291 
00292   static char buf[MAX_PATH];
00293   FioGetFullPath(buf, lengthof(buf), SP_AUTODOWNLOAD_DIR, dir, ci->filename);
00294   strecat(buf, compressed ? ".tar.gz" : ".tar", lastof(buf));
00295 
00296   return buf;
00297 }
00298 
00304 static bool GunzipFile(const ContentInfo *ci)
00305 {
00306 #if defined(WITH_ZLIB)
00307   bool ret = true;
00308   gzFile fin = gzopen(GetFullFilename(ci, true), "rb");
00309   FILE *fout = fopen(GetFullFilename(ci, false), "wb");
00310 
00311   if (fin == NULL || fout == NULL) {
00312     ret = false;
00313     goto exit;
00314   }
00315 
00316   byte buff[8192];
00317   while (!gzeof(fin)) {
00318     int read = gzread(fin, buff, sizeof(buff));
00319     if (read < 0 || (size_t)read != fwrite(buff, 1, read, fout)) {
00320       ret = false;
00321       break;
00322     }
00323   }
00324 
00325 exit:
00326   if (fin != NULL) gzclose(fin);
00327   if (fout != NULL) fclose(fout);
00328 
00329   return ret;
00330 #else
00331   NOT_REACHED();
00332 #endif /* defined(WITH_ZLIB) */
00333 }
00334 
00335 DEF_CONTENT_RECEIVE_COMMAND(Client, PACKET_CONTENT_SERVER_CONTENT)
00336 {
00337   if (this->curFile == NULL) {
00338     /* When we haven't opened a file this must be our first packet with metadata. */
00339     this->curInfo = new ContentInfo;
00340     this->curInfo->type     = (ContentType)p->Recv_uint8();
00341     this->curInfo->id       = (ContentID)p->Recv_uint32();
00342     this->curInfo->filesize = p->Recv_uint32();
00343     p->Recv_string(this->curInfo->filename, lengthof(this->curInfo->filename));
00344 
00345     if (!this->curInfo->IsValid()) {
00346       delete this->curInfo;
00347       this->curInfo = NULL;
00348       this->Close();
00349       return false;
00350     }
00351 
00352     if (this->curInfo->filesize != 0) {
00353       /* The filesize is > 0, so we are going to download it */
00354       const char *filename = GetFullFilename(this->curInfo, true);
00355       if (filename == NULL) {
00356         /* Unless that fails ofcourse... */
00357         DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
00358         ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, 0, 0);
00359         this->Close();
00360         return false;
00361       }
00362 
00363       this->curFile = fopen(filename, "wb");
00364     }
00365   } else {
00366     /* We have a file opened, thus are downloading internal content */
00367     size_t toRead = (size_t)(p->size - p->pos);
00368     if (fwrite(p->buffer + p->pos, 1, toRead, this->curFile) != toRead) {
00369       DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
00370       ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, 0, 0);
00371       this->Close();
00372       fclose(this->curFile);
00373       this->curFile = NULL;
00374 
00375       return false;
00376     }
00377 
00378     this->OnDownloadProgress(this->curInfo, (uint)toRead);
00379 
00380     if (toRead == 0) {
00381       /* We read nothing; that's our marker for end-of-stream.
00382        * Now gunzip the tar and make it known. */
00383       fclose(this->curFile);
00384       this->curFile = NULL;
00385 
00386       if (GunzipFile(this->curInfo)) {
00387         unlink(GetFullFilename(this->curInfo, true));
00388 
00389         TarListAddFile(GetFullFilename(this->curInfo, false));
00390 
00391         this->OnDownloadComplete(this->curInfo->id);
00392       } else {
00393         ShowErrorMessage(INVALID_STRING_ID, STR_CONTENT_ERROR_COULD_NOT_EXTRACT, 0, 0);
00394       }
00395     }
00396   }
00397 
00398   /* We ended this file, so clean up the mess */
00399   if (this->curFile == NULL) {
00400     delete this->curInfo;
00401     this->curInfo = NULL;
00402   }
00403 
00404   return true;
00405 }
00406 
00412 ClientNetworkContentSocketHandler::ClientNetworkContentSocketHandler() :
00413   NetworkContentSocketHandler(INVALID_SOCKET, NULL),
00414   curFile(NULL),
00415   curInfo(NULL),
00416   isConnecting(false)
00417 {
00418 }
00419 
00421 ClientNetworkContentSocketHandler::~ClientNetworkContentSocketHandler()
00422 {
00423   delete this->curInfo;
00424   if (this->curFile != NULL) fclose(this->curFile);
00425 
00426   for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) delete *iter;
00427 }
00428 
00429 class NetworkContentConnecter : TCPConnecter {
00430 public:
00431   NetworkContentConnecter(const NetworkAddress &address) : TCPConnecter(address) {}
00432 
00433   virtual void OnFailure()
00434   {
00435     _network_content_client.isConnecting = false;
00436     _network_content_client.OnConnect(false);
00437   }
00438 
00439   virtual void OnConnect(SOCKET s)
00440   {
00441     assert(_network_content_client.sock == INVALID_SOCKET);
00442     _network_content_client.isConnecting = false;
00443     _network_content_client.sock = s;
00444     _network_content_client.has_quit = false;
00445     _network_content_client.OnConnect(true);
00446   }
00447 };
00448 
00452 void ClientNetworkContentSocketHandler::Connect()
00453 {
00454   this->lastActivity = _realtime_tick;
00455 
00456   if (this->sock != INVALID_SOCKET || this->isConnecting) return;
00457   this->isConnecting = true;
00458   new NetworkContentConnecter(NetworkAddress(NETWORK_CONTENT_SERVER_HOST, NETWORK_CONTENT_SERVER_PORT));
00459 }
00460 
00464 void ClientNetworkContentSocketHandler::Close()
00465 {
00466   if (this->sock == INVALID_SOCKET) return;
00467   NetworkContentSocketHandler::Close();
00468 
00469   this->OnDisconnect();
00470 }
00471 
00476 void ClientNetworkContentSocketHandler::SendReceive()
00477 {
00478   if (this->sock == INVALID_SOCKET || this->isConnecting) return;
00479 
00480   if (this->lastActivity + IDLE_TIMEOUT < _realtime_tick) {
00481     this->Close();
00482     return;
00483   }
00484 
00485   fd_set read_fd, write_fd;
00486   struct timeval tv;
00487 
00488   FD_ZERO(&read_fd);
00489   FD_ZERO(&write_fd);
00490 
00491   FD_SET(this->sock, &read_fd);
00492   FD_SET(this->sock, &write_fd);
00493 
00494   tv.tv_sec = tv.tv_usec = 0; // don't block at all.
00495 #if !defined(__MORPHOS__) && !defined(__AMIGA__)
00496   select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv);
00497 #else
00498   WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL);
00499 #endif
00500   if (FD_ISSET(this->sock, &read_fd)) this->Recv_Packets();
00501   this->writable = !!FD_ISSET(this->sock, &write_fd);
00502   this->Send_Packets();
00503 }
00504 
00509 void ClientNetworkContentSocketHandler::DownloadContentInfo(ContentID cid)
00510 {
00511   /* When we tried to download it already, don't try again */
00512   if (this->requested.Contains(cid)) return;
00513 
00514   *this->requested.Append() = cid;
00515   assert(this->requested.Contains(cid));
00516   this->RequestContentList(1, &cid);
00517 }
00518 
00524 ContentInfo *ClientNetworkContentSocketHandler::GetContent(ContentID cid)
00525 {
00526   for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00527     ContentInfo *ci = *iter;
00528     if (ci->id == cid) return ci;
00529   }
00530   return NULL;
00531 }
00532 
00533 
00538 void ClientNetworkContentSocketHandler::Select(ContentID cid)
00539 {
00540   ContentInfo *ci = this->GetContent(cid);
00541   if (ci == NULL || ci->state != ContentInfo::UNSELECTED) return;
00542 
00543   ci->state = ContentInfo::SELECTED;
00544   this->CheckDependencyState(ci);
00545 }
00546 
00551 void ClientNetworkContentSocketHandler::Unselect(ContentID cid)
00552 {
00553   ContentInfo *ci = this->GetContent(cid);
00554   if (ci == NULL || !ci->IsSelected()) return;
00555 
00556   ci->state = ContentInfo::UNSELECTED;
00557   this->CheckDependencyState(ci);
00558 }
00559 
00561 void ClientNetworkContentSocketHandler::SelectAll()
00562 {
00563   for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00564     ContentInfo *ci = *iter;
00565     if (ci->state == ContentInfo::UNSELECTED) {
00566       ci->state = ContentInfo::SELECTED;
00567       this->CheckDependencyState(ci);
00568     }
00569   }
00570 }
00571 
00573 void ClientNetworkContentSocketHandler::SelectUpgrade()
00574 {
00575   for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00576     ContentInfo *ci = *iter;
00577     if (ci->state == ContentInfo::UNSELECTED && ci->upgrade) {
00578       ci->state = ContentInfo::SELECTED;
00579       this->CheckDependencyState(ci);
00580     }
00581   }
00582 }
00583 
00585 void ClientNetworkContentSocketHandler::UnselectAll()
00586 {
00587   for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00588     ContentInfo *ci = *iter;
00589     if (ci->IsSelected()) ci->state = ContentInfo::UNSELECTED;
00590   }
00591 }
00592 
00594 void ClientNetworkContentSocketHandler::ToggleSelectedState(const ContentInfo *ci)
00595 {
00596   switch (ci->state) {
00597     case ContentInfo::SELECTED:
00598     case ContentInfo::AUTOSELECTED:
00599       this->Unselect(ci->id);
00600       break;
00601 
00602     case ContentInfo::UNSELECTED:
00603       this->Select(ci->id);
00604       break;
00605 
00606     default:
00607       break;
00608   }
00609 }
00610 
00616 void ClientNetworkContentSocketHandler::ReverseLookupDependency(ConstContentVector &parents, const ContentInfo *child) const
00617 {
00618   for (ConstContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00619     const ContentInfo *ci = *iter;
00620     if (ci == child) continue;
00621 
00622     for (uint i = 0; i < ci->dependency_count; i++) {
00623       if (ci->dependencies[i] == child->id) {
00624         *parents.Append() = ci;
00625         break;
00626       }
00627     }
00628   }
00629 }
00630 
00636 void ClientNetworkContentSocketHandler::ReverseLookupTreeDependency(ConstContentVector &tree, const ContentInfo *child) const
00637 {
00638   *tree.Append() = child;
00639 
00640   /* First find all direct parents */
00641   for (ConstContentIterator iter = tree.Begin(); iter != tree.End(); iter++) {
00642     ConstContentVector parents;
00643     this->ReverseLookupDependency(parents, *iter);
00644 
00645     for (ConstContentIterator piter = parents.Begin(); piter != parents.End(); piter++) {
00646       tree.Include(*piter);
00647     }
00648   }
00649 }
00650 
00655 void ClientNetworkContentSocketHandler::CheckDependencyState(ContentInfo *ci)
00656 {
00657   if (ci->IsSelected() || ci->state == ContentInfo::ALREADY_HERE) {
00658     /* Selection is easy; just walk all children and set the
00659      * autoselected state. That way we can see what we automatically
00660      * selected and thus can unselect when a dependency is removed. */
00661     for (uint i = 0; i < ci->dependency_count; i++) {
00662       ContentInfo *c = this->GetContent(ci->dependencies[i]);
00663       if (c == NULL) {
00664         this->DownloadContentInfo(ci->dependencies[i]);
00665       } else if (c->state == ContentInfo::UNSELECTED) {
00666         c->state = ContentInfo::AUTOSELECTED;
00667         this->CheckDependencyState(c);
00668       }
00669     }
00670     return;
00671   }
00672 
00673   if (ci->state != ContentInfo::UNSELECTED) return;
00674 
00675   /* For unselection we need to find the parents of us. We need to
00676    * unselect them. After that we unselect all children that we
00677    * depend on and are not used as dependency for us, but only when
00678    * we automatically selected them. */
00679   ConstContentVector parents;
00680   this->ReverseLookupDependency(parents, ci);
00681   for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
00682     const ContentInfo *c = *iter;
00683     if (!c->IsSelected()) continue;
00684 
00685     this->Unselect(c->id);
00686   }
00687 
00688   for (uint i = 0; i < ci->dependency_count; i++) {
00689     const ContentInfo *c = this->GetContent(ci->dependencies[i]);
00690     if (c == NULL) {
00691       DownloadContentInfo(ci->dependencies[i]);
00692       continue;
00693     }
00694     if (c->state != ContentInfo::AUTOSELECTED) continue;
00695 
00696     /* Only unselect when WE are the only parent. */
00697     parents.Clear();
00698     this->ReverseLookupDependency(parents, c);
00699 
00700     /* First check whether anything depends on us */
00701     int sel_count = 0;
00702     bool force_selection = false;
00703     for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
00704       if ((*iter)->IsSelected()) sel_count++;
00705       if ((*iter)->state == ContentInfo::SELECTED) force_selection = true;
00706     }
00707     if (sel_count == 0) {
00708       /* Nothing depends on us */
00709       this->Unselect(c->id);
00710       continue;
00711     }
00712     /* Something manually selected depends directly on us */
00713     if (force_selection) continue;
00714 
00715     /* "Flood" search to find all items in the dependency graph*/
00716     parents.Clear();
00717     this->ReverseLookupTreeDependency(parents, c);
00718 
00719     /* Is there anything that is "force" selected?, if so... we're done. */
00720     for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
00721       if ((*iter)->state != ContentInfo::SELECTED) continue;
00722 
00723       force_selection = true;
00724       break;
00725     }
00726 
00727     /* So something depended directly on us */
00728     if (force_selection) continue;
00729 
00730     /* Nothing depends on us, mark the whole graph as unselected.
00731      * After that's done run over them once again to test their children
00732      * to unselect. Don't do it immediatelly because it'll do exactly what
00733      * we're doing now. */
00734     for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
00735       const ContentInfo *c = *iter;
00736       if (c->state == ContentInfo::AUTOSELECTED) this->Unselect(c->id);
00737     }
00738     for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
00739       this->CheckDependencyState(this->GetContent((*iter)->id));
00740     }
00741   }
00742 }
00743 
00744 void ClientNetworkContentSocketHandler::Clear()
00745 {
00746   for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) delete *iter;
00747 
00748   this->infos.Clear();
00749 }
00750 
00751 /*** CALLBACK ***/
00752 
00753 void ClientNetworkContentSocketHandler::OnConnect(bool success)
00754 {
00755   for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); /* nothing */) {
00756     ContentCallback *cb = *iter;
00757     cb->OnConnect(success);
00758     if (iter != this->callbacks.End() && *iter == cb) iter++;
00759   }
00760 }
00761 
00762 void ClientNetworkContentSocketHandler::OnDisconnect()
00763 {
00764   for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); /* nothing */) {
00765     ContentCallback *cb = *iter;
00766     cb->OnDisconnect();
00767     if (iter != this->callbacks.End() && *iter == cb) iter++;
00768   }
00769 }
00770 
00771 void ClientNetworkContentSocketHandler::OnReceiveContentInfo(const ContentInfo *ci)
00772 {
00773   for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); /* nothing */) {
00774     ContentCallback *cb = *iter;
00775     cb->OnReceiveContentInfo(ci);
00776     if (iter != this->callbacks.End() && *iter == cb) iter++;
00777   }
00778 }
00779 
00780 void ClientNetworkContentSocketHandler::OnDownloadProgress(const ContentInfo *ci, uint bytes)
00781 {
00782   for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); /* nothing */) {
00783     ContentCallback *cb = *iter;
00784     cb->OnDownloadProgress(ci, bytes);
00785     if (iter != this->callbacks.End() && *iter == cb) iter++;
00786   }
00787 }
00788 
00789 void ClientNetworkContentSocketHandler::OnDownloadComplete(ContentID cid)
00790 {
00791   ContentInfo *ci = this->GetContent(cid);
00792   if (ci != NULL) {
00793     ci->state = ContentInfo::ALREADY_HERE;
00794   }
00795 
00796   for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); /* nothing */) {
00797     ContentCallback *cb = *iter;
00798     cb->OnDownloadComplete(cid);
00799     if (iter != this->callbacks.End() && *iter == cb) iter++;
00800   }
00801 }
00802 
00803 #endif /* ENABLE_NETWORK */

Generated on Mon Feb 16 23:12:07 2009 for openttd by  doxygen 1.5.6