#include #include "transfer_storage.h" int gdl_item::gdl_id_counter = 1; static const char *X_STATUS_NAMES[] = { "Removing", "Closed", "Queued", "DCTC-Queued", "Waiting", "Trying", "Downloading", "Uploading", "Closing", ""}; // // Add a new transfer, unless it already exists. // transfer_item &gdl_item::add_source(const transfer_item &src) { list::iterator i = find(sources.begin(), sources.end(), src); if (i == sources.end()) { sources.push_front(src); return sources.front(); } else return (*i); } // // Runs through the sources and removes all outdated ones, unless they // were locally queued and haven't yet been connected to. // void gdl_item::remove_outdated(long timestamp) { list::iterator i = sources.begin(); while (i!=sources.end()) { list::iterator j = i++; if ((*j).timestamp < timestamp && (*j).status != X_QUEUED_LOCAL) sources.erase(j); } } // // Sets status of all outdated sources to queued, unless they're queued locally. // void gdl_item::mark_outdated(long timestamp) { list::iterator i = sources.begin(); while (i!=sources.end()) { list::iterator j = i++; if ((*j).timestamp < timestamp && (*j).status != X_QUEUED_LOCAL) { (*j).status = X_CLOSED; } } } // // Runs through the sources and removes all marked for removal. // void gdl_item::delete_removed() { list::iterator i = sources.begin(); while (i!=sources.end()) { list::iterator j = i++; if ((*j).status == X_REMOVED) { sources.erase(j); } } } // // This is used to update existing GDLs. // // Calls update_source() and update_completed() for each 'ddd' and 'eee' entry, respectively. // void gdl_item::update(const long ts, const unsigned int id, const ULLINT fsize, const ULLINT foffs, const ULLINT frecv, const int s_time, const ULLINT frecv_last10, const QString &running_dls, const QString &completed_dls) { timestamp = ts; _id = id; size = fsize; offset = foffs; recv = frecv; recv_last10 = frecv_last10; start_time = s_time; // Update running downloads. QString entry = running_dls.section('|', 0, 0); for(int i=0; entry != ""; entry = running_dls.section('|', i, i)) { update_source(entry); i++; } // Update completed downloads. entry = completed_dls.section('|', 0, 0); for(int i=0; entry != ""; entry = completed_dls.section('|', i, i)) { update_completed(entry); i++; } } // // This is used to add/update a download from one source (transfer_item). // // Parses a running download entry (substring of the 'ddd' part of the // GLSTC entry). // void gdl_item::update_source(const QString &src_str) { // ddd contains 0 or more entries having the following format // and separated by |. ddd ends with an empty string. // This is the list of sources files of the GDL. // xx$yy$zz$tt // where xx is a nickname // yy is a remote filename // zz is the size of the remote filename // tt is the status: 'W' for waiting, 'T' for // trying and 'Rhhh[iii;jjj]' for running (hhh is // the number of bytes downloaded in the range, iii // is the download start position and jjj is the // download end position (excluded). // Set default range to 0-1, in case download isn't running yet. transfer_status dl_status = X_QUEUED_REMOTE; ULLINT filesize=0, recvsize=0, range_start=0, range_end=1; // Parse username and filename from the dl entry. QString username = src_str.section('$', 0, 0); QString filename = src_str.section('$', 1, 1); if (username.isEmpty() || filename.isEmpty()) return; // Try to find a matching entry in the sources list. // Not using find() to avoid allocating a new transfer_item instance. bool found=false; list::iterator i = sources.begin(); while (!found && i!=sources.end()) { if (!(*i).user_name.isEmpty() && !(*i).file_name.isEmpty()) { if ((*i).user_name == username || (*i).file_name == filename) found = true; } if (!found) i++; } // If we've found no match, then this is a new download source being // added, and we prepend it to the sources list. // After this, iterator i will point to a valid transfer_item in the sources list. if (!found) { sources.push_front(transfer_item(_id, username, filename)); i = sources.begin(); } // Now we parse the rest of the info. if ((src_str.section('$', 2, 2)).toLong()==-1) filesize = 0; else filesize = (src_str.section('$', 2, 2)).toULong(); // Extract the status QString status_str = src_str.section('$', 3, 3); QString status = status_str.left(1); if (status == "W") dl_status = X_WAITING; else if (status == "T") dl_status = X_TRYING; else if (status == "R") { dl_status = X_DOWNLOADING; // Parse received size and download range. int pos = status_str.find('['); recvsize = (status_str.mid(1,pos-1)).toULong(); // get rid of leading 'Rhhh[' and trailing ']' status_str = status_str.mid(1+pos,status_str.length()-2-pos); range_start = (status_str.section(';', 0, 0)).toULong(); range_end = (status_str.section(';', 1, 1)).toULong(); } // update transfer_item (*i).update(filename, filesize, dl_status, recvsize, range_start, range_end); // set item's timestamp to this GDL's timestamp (*i).timestamp = timestamp; } // // This is used to add/update a completed download from a source. // // Parses a completed download entry (substring of the 'eee' part of // the GLSTC entry). // void gdl_item::update_completed(const QString &completed_str) { // eee contains 0 or more entries having the following format // and separated by |. eee ends with an empty string. // This is the list of downloaded segments of the GDL // xx$[iii;jjj] // where xx is the name of the filename containing the segment // iii is the start position of the segment and jjj is // the end position of the segment (excluded). // file name ends before '$' QString fname = completed_str.section('$', 0, 0); list::iterator i = completed.begin(); while (i!=completed.end() && (*i).file_name != fname) { i++; } // Only parse range if this is a new 'completed' item. if (i==completed.end()) { QString str = completed_str.section('$', 1, 1); // get the range string [iii;jjj] str = str.mid(1,str.length()-2); // get rid of leading '[' and trailing ']' ULLINT r1 = (str.section(';', 0, 0)).toULong(); ULLINT r2 = (str.section(';', 1, 1)).toULong(); completed.push_front(complete_item(fname, r1, r2)); } } // // Time (seconds) since this GDL was started/attached. // // Returned value is always a positive integer not less than 1. // int gdl_item::elapsed_time() const { int delta = (int)time(NULL)-start_time; return delta<1 ? 1 : delta; } // // This returns number of bytes already received. // // Returns recv. // // TODO: Since DCTC reports a value that is not fully accurate, // traverse running and completed downloads and calcs a union of // completed ranges. // ULLINT gdl_item::recv_size() const { return recv; } // // This calculates number of bytes left to receive. // // Uses recv_size() to get download progress. // ULLINT gdl_item::recv_left() const { return (size - recv_size()); } // // This returns an estimate of the GDL transfer rate (bytes/s). // // IDEAS: Adjust the approximation using a more accurate recv_size and perhaps some filter. // float gdl_item::ETR() const { float r = 0; list::const_iterator it = sources.begin(); while (it != sources.end()) { r += (float)(it->bps()); it++; } return r; /* if (recv_last10==0) return (float)recv_size() / (float)elapsed_time(); else return (float)recv_last10 / 10.0f; */ } // // Estimates time left until the completion of this GDL, in seconds. // -1: unknown // int gdl_item::ETC() const { float rate = ETR(); if (rate < 2.0f) return -1; else return (int)(recv_left() / rate); } // // Calculates total download progress (in percent). // float gdl_item::progress() const { return (float)recv_size() / (float)size; } //X_QUEUED_LOCAL=0, X_QUEUED_REMOTE, X_WAITING, X_TRYING, X_DOWNLOADING, X_CLOSING}; QString gdl_item::status_str() const { if (sources.empty()) return QString("No sources"); transfer_status s = X_QUEUED_LOCAL; // Get the highest status of all download sources. list::const_iterator i = sources.begin(); while (i!=sources.end()) { s = (*i).status > s ? (*i).status : s; i++; } return QString(X_STATUS_NAMES[s]); } QString transfer_item::status_str() const { return QString(X_STATUS_NAMES[status]); } /* * * $Log: transfer_storage.cc,v $ * Revision 1.6 2004/07/25 21:09:34 estrato * adjusted dl resume delay and dl items display * * Revision 1.5 2004/03/07 05:24:12 estrato * fixed a bunch of annoying bugs with transfers * * Revision 1.4 2004/02/27 11:15:02 estrato * fixed autoresuming and attaching to gdls * * Revision 1.3 2003/08/18 12:19:43 estrato * Old transfer dialog now completely replaced, but some functionality is gone. Will add complete functionality in next commit. * * Revision 1.2 2003/08/16 21:34:19 estrato * New transfer dialog update, almost all internal functions done. Will replaceold transferdlg in next commit. * * Revision 1.1 2003/08/14 23:30:45 estrato * New transfer widget, basic storage and view functionality, no signals connected yet. * * * */