network_content.cpp

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

Generated on Wed Dec 23 20:12:49 2009 for OpenTTD by  doxygen 1.5.6