/* -*- c++ -*- * * donkeyprotocol.cpp * * Copyright (C) 2003 Petter E. Stokke * Copyright (C) 2003 Sebastian Sauer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "donkeyprotocol.h" #include "donkeysocket.h" #include "fileinfo.h" #include "serverinfo.h" #include "network.h" #include "clientinfo.h" #include "shareinfo.h" #include "searchinfo.h" #include "hostmanager.h" #include "hostiface.h" #include "donkeyhost.h" #include "searchquery.h" #include #include DonkeyProtocol::DonkeyProtocol(bool poll, QObject *parent) : ProtocolInterface("mldonkey", parent) { uname = "admin"; passwd = ""; donkeyError = NoError; connectedservers = 0; proto = MIN_PROTOCOL_VERSION; wantpoll = poll; download.setAutoDelete(true); downloaded.setAutoDelete(true); servers.setAutoDelete(true); networks.setAutoDelete(true); clients.setAutoDelete(true); shares.setAutoDelete(true); rooms.setAutoDelete(true); searches.setAutoDelete(true); unmappedResults.setAutoDelete(true); connect(&sock, SIGNAL(readyMessage()), this, SLOT(processMessage())); connect(&sock, SIGNAL(connectionClosed()), this, SLOT(socketDisconnected())); connect(&sock, SIGNAL(error(int)), this, SLOT(socketError(int))); connect(&sock, SIGNAL(delayedCloseFinished()), this, SLOT(socketDisconnected())); } DonkeyProtocol::~DonkeyProtocol() { } void DonkeyProtocol::setPassword(const QString& username, const QString& pwd) { uname = username; passwd = pwd; } void DonkeyProtocol::setPassword(const QString& pwd) { uname = "admin"; passwd = pwd; } const QString& DonkeyProtocol::username() { return uname; } const QString& DonkeyProtocol::password() { return passwd; } bool DonkeyProtocol::isConnected() { return (sock.state() == QSocket::Connected); } bool DonkeyProtocol::connectToCore() { donkeyError = NoError; if (isConnected()) { if (! disconnectFromCore()) return false; } else flushState(); DonkeyHost *host = (DonkeyHost*)getHost(); if(host) { setPassword(host->username(), host->password()); sock.connectDonkey(host->address(), host->port()); } else { sock.connectDonkey(); } return true; } bool DonkeyProtocol::disconnectFromCore() { // The QSocket-documentation says that unwritten data will be written // on socket.close(). But that doesn't seem to be the case if // disconnectFromCore() is called on KMLDonkey::queryClose() cause // the stopSearch()'s called at SearchPage::stopAllSearches() got // lost. So, we've explicit to call flush() to be sure. sock.flush(); sock.close(); kdDebug() << "Socket closed." << endl; if (sock.state() == QSocket::Idle) emit signalDisconnected(donkeyError); flushState(); return true; } void DonkeyProtocol::flushState() { download.clear(); downloaded.clear(); upload.clear(); servers.clear(); networks.clear(); clients.clear(); shares.clear(); searches.clear(); unmappedResults.clear(); options.clear(); friends.clear(); rooms.clear(); m_sectionOptions.clear(); m_pluginOptions.clear(); consoleCallbacks.clear(); defSearches.clear(); connectedservers = 0; downloadstarted = false; } void DonkeyProtocol::socketDisconnected() { emit signalDisconnected(donkeyError); flushState(); } void DonkeyProtocol::socketError(int err) { switch (err) { case QSocket::ErrConnectionRefused: emit signalDisconnected(ConnectionRefusedError); break; case QSocket::ErrHostNotFound: emit signalDisconnected(HostNotFoundError); break; case QSocket::ErrSocketRead: donkeyError = CommunicationError; disconnectFromCore(); break; } } void DonkeyProtocol::pruneClientRecord(int clientno) { QIntDictIterator it(download); for (; it.current(); ++it) { it.current()->removeSource(clientno); emit fileUpdated(it.current()->fileNo()); emit fileSourceRemoved(it.current()->fileNo(), clientno); } if (friends.remove(clientno)) emit friendRemoved(clientno); } const int DonkeyProtocol::protocolVersion() { return proto; } void DonkeyProtocol::processMessage() { DonkeyMessage* msg; while ((msg = sock.popMessage())) { DonkeyMessage* out; QString baz; emit messageReceived(msg); switch (msg->opcode()) { case CoreProtocol: proto = msg->readInt32(); // FIXME: We might read the protocol 26 max_to_gui and max_from_gui values here (both int32). // We don't, because we don't really need them for anything useful right now. kdDebug() << "CoreProtocol message, version " << proto << endl; if (proto < MIN_PROTOCOL_VERSION) { kdDebug() << "Obsolete protocol version!" << endl; donkeyError = IncompatibleProtocolError; disconnectFromCore(); break; } out = new DonkeyMessage(GuiProtocol); out->writeInt32(MAX_PROTOCOL_VERSION); sock.sendMessage(*out); coreProto = proto; if (proto > MAX_PROTOCOL_VERSION) proto = MAX_PROTOCOL_VERSION; kdDebug() << "Using protocol " << proto << endl; delete out; if (wantpoll) { out = new DonkeyMessage(GuiExtensions); out->writeInt16(1); out->writeInt32(1); out->writeInt8(1); sock.sendMessage(*out); delete out; } out = new DonkeyMessage(Password); out->writeString(passwd); out->writeString(uname); sock.sendMessage(*out); delete out; if (proto >= 31) requestVersion(); emit signalConnected(); break; case Console: { baz = msg->readString(); bool ok = false; if (consoleCallbacks.count() > 0) { QRegExp rx("^\n[\\-]+\nEval[\\s]command:[\\s](.+)"); if (rx.search(baz) >= 0) { QString s = rx.cap(1); int pos = s.find("\n"); if (pos > 0) { QString cmd = s.left(pos).stripWhiteSpace(); QString res = s.mid(pos + 2, s.length() - pos - 4).stripWhiteSpace(); ConsoleCallbackInterface* cb = consoleCallbacks[cmd]; if (cb && !res.startsWith("No such command ")) { consoleCallbacks.remove(cmd); cb->callback(cmd, res); ok = true; } } } } if (! ok) emit consoleMessage(baz); } break; case BadPassword: kdDebug() << "Bad password!" << endl; donkeyError = AuthenticationError; disconnectFromCore(); break; case Client_stats_v1: case Client_stats_v2: case Client_stats_v3: kdDebug() << "Obsolete client stats message received" << endl; break; case Client_stats: { int64 ul = msg->readInt64(); int64 dl = msg->readInt64(); int64 sh = msg->readInt64(); int32 nsh = msg->readInt32(); int32 tul = msg->readInt32(); int32 tdl = msg->readInt32(); int32 uul = msg->readInt32(); int32 udl = msg->readInt32(); int32 ndl = msg->readInt32(); int32 ncp = msg->readInt32(); clientstatsmap.clear(); int i,j = msg->readInt16(); for (i=0; ireadInt32(); int s = msg->readInt32(); clientstatsmap.replace(nw, s); } emit clientStats(ul,dl,sh,nsh,tul,tdl,uul,udl,ndl,ncp,&clientstatsmap); } break; case File_add_source: { int fn = msg->readInt32(); int cl = msg->readInt32(); FileInfo* file = findDownloadFileNo(fn); if (file) { file->addSource(cl); emit fileUpdated(fn); emit fileSourceUpdated(fn,cl); } } break; case File_remove_source: { int fn = msg->readInt32(); int cl = msg->readInt32(); FileInfo* file = findDownloadFileNo(fn); if (file) { file->removeSource(cl); emit fileUpdated(fn); emit fileSourceRemoved(fn,cl); } } break; case File_update_availability: { int fn = msg->readInt32(); int cl = msg->readInt32(); QString av = msg->readString(); FileInfo* file = findDownloadFileNo(fn); if (file) { file->updateAvailability(cl, av); emit fileUpdated(fn); emit fileSourceUpdated(fn,cl); } } break; case Client_info: { ClientInfo* client = new ClientInfo(msg, proto); clients.replace(client->clientNo(), client); if (client->clientType() == ClientInfo::FriendClient) { if (!friends.contains(client->clientNo())) { friends.append(client->clientNo()); emit friendUpdated(client->clientNo()); } } else if (friends.remove(client->clientNo())) emit friendRemoved(client->clientNo()); if (client->clientState() == ClientInfo::Removed) { pruneClientRecord(client->clientNo()); clients.remove(client->clientNo()); emit clientRemoved(client->clientNo()); if (upload.contains(client->clientNo())) { upload.remove(client->clientNo()); emit uploadRemoved(client->clientNo()); } } else { emit clientUpdated(client->clientNo()); if (upload.contains(client->clientNo())) { if (upload[client->clientNo()]) emit uploadUpdated(client->clientNo()); else { upload.remove(client->clientNo()); emit uploadRemoved(client->clientNo()); } } } } break; case Client_state: { int clno = msg->readInt32(); ClientInfo* client = findClientNo(clno); if (!client) { refreshClientInfo(clno); break; } client->setClientState(msg, proto); switch (client->clientState()) { case ClientInfo::Removed: emit clientRemoved(clno); pruneClientRecord(clno); clients.remove(clno); break; default: emit clientUpdated(clno); break; } } break; case Client_friend: { int clno = msg->readInt32(); ClientInfo* client = findClientNo(clno); if (!client) { refreshClientInfo(clno); break; } client->setClientType(msg, proto); switch (client->clientType()) { case ClientInfo::FriendClient: if (!friends.contains(clno)) { friends.append(clno); emit friendUpdated(clno); } break; default: if (friends.remove(clno)) emit friendRemoved(clno); } emit clientUpdated(clno); } break; /* case Client_file: { kdDebug() << "Client_file message: " << msg->readInt32() << " \"" << msg->readString() << "\" " << msg->readInt32() << endl; } break; */ case DownloadFiles_v1: case DownloadFiles_v2: case DownloadFiles_v3: kdDebug() << "Obsolete download files message received" << endl; break; case DownloadFiles_v4: case DownloadFiles: { download.clear(); int i, j = msg->readInt16(); for (i=0; ifileNo()); if (fo) fo->updateFileInfo(fi); else download.replace(fi->fileNo(), fi); emit fileUpdated(fi->fileNo()); } emit updatedDownloadFiles(); } break; case File_downloaded_v1: case File_downloaded: { int fn = msg->readInt32(); FileInfo* fi = findDownloadFileNo(fn); if (fi) { fi->updateDownloadStatus(msg, proto); switch (fi->fileState()) { case FileInfo::Shared: case FileInfo::Cancelled: case FileInfo::Aborted: emit fileRemoved(fn); download.remove(fi->fileNo()); break; default: emit fileUpdated(fn); break; } } } break; case DownloadedFiles_v1: kdDebug() << "Obsolete downloaded files message received" << endl; break; case DownloadedFiles_v2: case DownloadedFiles: { downloaded.clear(); int i, j = msg->readInt16(); for (i=0; ifileNo()); if (fo) fo->updateFileInfo(fi); else downloaded.replace(fi->fileNo(), fi); } emit updatedDownloadedFiles(); } break; case File_info_v1: case File_info_v2: kdDebug() << "Obsolete file info message received" << endl; break; case File_info_v3: case File_info: { FileInfo* fi = findDownloadFileNo(msg->readInt32()); msg->resetPosition(); bool isnew = ! fi; if (isnew) { fi = new FileInfo(msg, proto); download.replace(fi->fileNo(), fi); } else { fi->updateFileInfo(msg, proto); } switch (fi->fileState()) { case FileInfo::Shared: case FileInfo::Cancelled: case FileInfo::Aborted: emit fileRemoved(fi->fileNo()); download.remove(fi->fileNo()); break; default: emit fileUpdated(fi->fileNo()); if (isnew) emit fileAdded(fi->fileNo(), downloadstarted); break; } } break; case ConnectedServers: { servers.clear(); connectedservers = 0; int i, j = msg->readInt16(); for (i=0; iserverNo(), si); if (si->serverState() == ClientInfo::Connected || si->serverState() == ClientInfo::Connected2 || si->serverState() == ClientInfo::Connected3) connectedservers++; } emit updatedConnectedServers(); } break; case Server_info_v1: case Server_info: { ServerInfo* si = new ServerInfo(msg, proto); ServerInfo* oldsi = findServerNo(si->serverNo()); ClientInfo::State newstate = si->serverState(), oldstate = oldsi ? oldsi->serverState() : ClientInfo::NotConnected; if ((oldstate == ClientInfo::Connected || oldstate == ClientInfo::Connected2 || oldstate == ClientInfo::Connected3) && (newstate != ClientInfo::Connected && newstate != ClientInfo::Connected2 && newstate != ClientInfo::Connected3)) connectedservers--; if ((oldstate != ClientInfo::Connected && oldstate != ClientInfo::Connected2 && oldstate != ClientInfo::Connected3) && (newstate == ClientInfo::Connected || newstate == ClientInfo::Connected2 || newstate == ClientInfo::Connected3)) connectedservers++; servers.replace(si->serverNo(), si); switch (si->serverState()) { case ClientInfo::Removed: emit serverRemoved(si->serverNo()); servers.remove(si->serverNo()); break; default: emit serverUpdated(si->serverNo()); break; } } break; case Server_state: { int sn = msg->readInt32(); ServerInfo* si = findServerNo(sn); if (!si) { kdDebug() << "Core sent an invalid server number!" << endl; break; } ClientInfo::State oldstate = si->serverState(); si->updateServerState(msg, proto); ClientInfo::State newstate = si->serverState(); if ((oldstate == ClientInfo::Connected || oldstate == ClientInfo::Connected2 || oldstate == ClientInfo::Connected3) && (newstate != ClientInfo::Connected && newstate != ClientInfo::Connected2 && newstate != ClientInfo::Connected3)) connectedservers--; if ((oldstate != ClientInfo::Connected && oldstate != ClientInfo::Connected2 && oldstate != ClientInfo::Connected3) && (newstate == ClientInfo::Connected || newstate == ClientInfo::Connected2 || newstate == ClientInfo::Connected3)) connectedservers++; switch (si->serverState()) { case ClientInfo::Removed: emit serverRemoved(sn); servers.remove(si->serverNo()); break; default: emit serverUpdated(sn); break; } } break; case Network_info: { Network* nw = new Network(msg, proto); networks.replace(nw->networkNo(), nw); emit networkUpdated(nw->networkNo()); } break; case Shared_file_info_v1: case Shared_file_info: { ShareInfo* si = new ShareInfo(msg, proto); shares.replace(si->shareNo(), si); emit shareUpdated(si->shareNo()); } break; case Shared_file_upload: { ShareInfo* si = findShareNo(msg->readInt32()); if (si) { si->updateShare(msg, proto); emit shareUpdated(si->shareNo()); } } break; case Shared_file_unshared: { int shno = msg->readInt32(); if (shares.remove(shno)) emit shareRemoved(shno); } break; case Options_info: { int i, j = msg->readInt16(); for (i=0; ireadString(); value = msg->readString(); options.replace(key,value); } emit optionsUpdated(); } break; case DefineSearches: { defSearches.clear(); defSearch = QString::null; int i, j = msg->readInt16(); for (i=0; ireadString(); if(i==0) defSearch = name; // first item is always the default one defSearches.replace(name, SearchQuery::getQuery(msg)); } emit definedSearchesUpdated(); } break; // Following both messages are used to transfer the Searchresults back. // First Result_info's are recieved. Later the Search_result's defines // to what Search the previous noted Result_info's belongs too. // MLDonkey does cache searches. So, if you start again a search for // something that was previously searched for, it returns only // Search_result's. case Result_info: { ResultInfo *si = new ResultInfo(msg, proto); unmappedResults.replace(si->resultNo(), si); } break; case Search_result: { int searchnum = msg->readInt32(); int resultnum = msg->readInt32(); ResultInfo* ri = unmappedResults[resultnum]; if (!ri) return; SearchInfo *si = searches[searchnum]; if (!si) { si = new SearchInfo(searchnum); searches.replace(searchnum, si); } si->addResult(ri); emit searchUpdated(searchnum, ri); } break; /* case Pending: { int i, j = msg->readInt16(); QString o("Pending: "); for (i=0; ireadInt32(); o += QString::number(v) + " "; } kdDebug() << o << endl; } break; */ /* // We get those message as result of getSearch(searchnum) and // getSearches() requests. case Search: { int searchnum = msg->readInt32(); //kdDebug() << "Search num=" << searchnum << endl; SearchInfo *si = searches[searchnum]; if (! si) { si = new SearchInfo(searchnum); searches.replace(searchnum, si); } si->setQuery(msg, proto); emit searchRequest(searchnum); } break; */ case Client_file: { int clno = msg->readInt32(); QString dir = msg->readString(); int result = msg->readInt32(); emit clientFileListing(clno, dir, result); } break; case CleanTables: { QIntDict newClients; int i, j = msg->readInt16(); for (i=0; ireadInt32()); if (cl) newClients.replace(cl->clientNo(), cl); } QIntDictIterator cit(clients); for (; cit.current(); ++cit) { emit clientRemoved(cit.current()->clientNo()); pruneClientRecord(cit.current()->clientNo()); } clients = newClients; QIntDict newServers; j = msg->readInt16(); for (i=0; ireadInt32()); if (si) newServers.replace(si->serverNo(), si); } QIntDictIterator sit(servers); for (; sit.current(); ++sit) emit serverRemoved(sit.current()->serverNo()); servers = newServers; // Don't know if operator=() copies the autodelete state, best to be certain. clients.setAutoDelete(true); servers.setAutoDelete(true); } break; case MessageFromClient: { int clno = msg->readInt32(); if (!findClientNo(clno)) refreshClientInfo(clno); emit messageFromClient(clno, msg->readString()); } break; case Add_section_option: { DonkeyOption opt(msg, proto); m_sectionOptions.append(opt); emit newSectionOption(opt); } break; case Add_plugin_option: { DonkeyOption opt(msg, proto); m_pluginOptions.append(opt); emit newPluginOption(opt); } break; case Room_info_v2: case Room_info: { int roomno = msg->readInt32(); RoomInfo* ri = rooms.find(roomno); if (ri) ri->update(msg, proto); else { ri = new RoomInfo(msg, proto, roomno); rooms.replace(roomno, ri); } emit roomUpdated(roomno); } break; case Room_message: { int roomno = msg->readInt32(); RoomInfo* ri = rooms.find(roomno); if (ri) { RoomMessage* rm = new RoomMessage(msg, proto); ri->addMessage(rm); emit roomMessage(roomno, rm); } else kdDebug() << QString("Room_message for not existing room %1").arg(roomno) << endl; } break; case Room_add_user: { int roomnum = msg->readInt32(); int usernum = msg->readInt32(); emit roomAddUser(roomnum, usernum); kdDebug() << "Room_add_user roomnum=" << roomnum << " usernum=" << usernum << endl; } break; case Room_remove_user: { int roomnum = msg->readInt32(); int usernum = msg->readInt32(); emit roomRemoveUser(roomnum, usernum); kdDebug() << "Room_remove_user roomnum=" << roomnum << " usernum=" << usernum << endl; } break; case UploadFiles: { for (QMap::Iterator it = upload.begin(); it != upload.end(); ++it) it.data() = false; // We use the bool-value to indicate if an uploaditem gots dirty (removed). int i, j = msg->readInt16(); for (i=0; ireadInt32(); upload.replace(num, true); refreshClientInfo(num); } for (QMap::Iterator it = upload.begin(); it != upload.end(); ++it) if (! it.data()) refreshClientInfo(it.key()); } break; case Version: { QString version = msg->readString(); emit coreVersion(version); kdDebug() << "Core reported version " << version << endl; } break; default: emit unhandledMessage(msg); break; } delete msg; } } void DonkeyProtocol::updateDownloadFiles() { sock.sendMessage(DonkeyMessage(GetDownloadFiles)); } void DonkeyProtocol::updateDownloadedFiles() { sock.sendMessage(DonkeyMessage(GetDownloadedFiles)); } void DonkeyProtocol::updateConnectedServers() { sock.sendMessage(DonkeyMessage(GetConnectedServers)); } const QIntDict& DonkeyProtocol::downloadFiles() { return download; } const QIntDict& DonkeyProtocol::downloadedFiles() { return downloaded; } const QIntDict& DonkeyProtocol::connectedServers() { return servers; } const QIntDict& DonkeyProtocol::availableNetworks() { return networks; } const QIntDict& DonkeyProtocol::clientList() { return clients; } const QIntDict& DonkeyProtocol::sharedFiles() { return shares; } const QValueList& DonkeyProtocol::friendList() { return friends; } FileInfo* DonkeyProtocol::findDownloadFileNo(int fileno) { return download[fileno]; } FileInfo* DonkeyProtocol::findDownloadedFileNo(int fileno) { return downloaded[fileno]; } ServerInfo* DonkeyProtocol::findServerNo(int serverno) { return servers[serverno]; } Network* DonkeyProtocol::findNetworkNo(int nwno) { return networks[nwno]; } ClientInfo* DonkeyProtocol::findClientNo(int clno) { return clients[clno]; } ShareInfo* DonkeyProtocol::findShareNo(int shno) { return shares[shno]; } void DonkeyProtocol::sendConsoleMessage(const QString& msg, ConsoleCallbackInterface* callback) { if (callback) consoleCallbacks.replace(msg, callback); DonkeyMessage out(Command); out.writeString(msg); sock.sendMessage(out); } void DonkeyProtocol::saveFile(int fileno, const QString& name) { DonkeyMessage out(SaveFile); out.writeInt32(fileno); out.writeString(name); sock.sendMessage(out); } void DonkeyProtocol::pauseFile(int fileno, bool pause) { DonkeyMessage out(SwitchDownload); out.writeInt32(fileno); out.writeInt8((int8)!pause); sock.sendMessage(out); } void DonkeyProtocol::cancelFile(int fileno) { DonkeyMessage out(RemoveDownload_query); out.writeInt32(fileno); sock.sendMessage(out); } void DonkeyProtocol::setFilePriority(int fileno, int pri) { DonkeyMessage out(SetFilePriority); out.writeInt32(fileno); out.writeInt32(pri); sock.sendMessage(out); } void DonkeyProtocol::verifyFileChunks(int fileno) { DonkeyMessage out(VerifyAllChunks); out.writeInt32(fileno); sock.sendMessage(out); } void DonkeyProtocol::getFileFormat(int fileno) { DonkeyMessage out(QueryFormat); out.writeInt32(fileno); sock.sendMessage(out); } void DonkeyProtocol::previewFile(int fileno) { DonkeyMessage out(Preview); out.writeInt32(fileno); sock.sendMessage(out); } void DonkeyProtocol::retryFile(int fileno) { DonkeyMessage out(ConnectAll); out.writeInt32(fileno); sock.sendMessage(out); } void DonkeyProtocol::submitURL(const QString& url) { downloadstarted = true; QRegExp rx("^(ftp|http)://.+"); if (rx.search(url) >= 0 && ! url.lower().endsWith(".torrent")) { sendConsoleMessage("http \"" + url + "\""); } else { DonkeyMessage out(Url); out.writeString(url); sock.sendMessage(out); } } void DonkeyProtocol::sendMessage(const DonkeyMessage& msg) { sock.sendMessage(msg); } void DonkeyProtocol::connectMoreServers() { sock.sendMessage(DonkeyMessage(ConnectMore_query)); } void DonkeyProtocol::cleanOldServers() { sock.sendMessage(DonkeyMessage(CleanOldServers)); } void DonkeyProtocol::addServer(int network, const QString& ip, int16 port) { DonkeyMessage out(AddServer_query); out.writeInt32(network); out.writeInt8(1); // True means following IP address is a string out.writeString(ip); out.writeInt16(port); sock.sendMessage(out); } void DonkeyProtocol::removeServer(int serverno) { DonkeyMessage out(RemoveServer_query); out.writeInt32(serverno); sock.sendMessage(out); } void DonkeyProtocol::blacklistServer(int serverno) { ServerInfo* si = findServerNo(serverno); if (si) sendConsoleMessage("bs " + si->serverAddress()); } void DonkeyProtocol::getServerInfo(int serverno) { DonkeyMessage out(GetServer_info); out.writeInt32(serverno); sock.sendMessage(out); } void DonkeyProtocol::getServerUsers(int serverno) { DonkeyMessage out(GetServer_users); out.writeInt32(serverno); sock.sendMessage(out); } void DonkeyProtocol::connectServer(int serverno) { DonkeyMessage out(ConnectServer); out.writeInt32(serverno); sock.sendMessage(out); } void DonkeyProtocol::disconnectServer(int serverno) { DonkeyMessage out(DisconnectServer); out.writeInt32(serverno); sock.sendMessage(out); } SearchInfo* DonkeyProtocol::findSearchNo(int num) { return searches[num]; } const QIntDict& DonkeyProtocol::activeSearches() { return searches; } const QString& DonkeyProtocol::definedSearch() { return defSearch; } const QMap DonkeyProtocol::definedSearches() { return defSearches; } void DonkeyProtocol::startSearch(int searchNum, SearchQuery* query, int maxHits, SearchType searchType, int network) { DonkeyMessage out(Search_query); out.writeInt32((int32)searchNum); // search_num to identify searches query->writeQuery(out); // write the query into the message out.writeInt32((int32)maxHits); // search_max_hits out.writeInt8((int8)searchType); // search_type out.writeInt32((int32)network); // network to search sock.sendMessage(out); } void DonkeyProtocol::stopSearch(int searchNum) { DonkeyMessage out(CloseSearch); out.writeInt32(searchNum); out.writeInt8(true); sock.sendMessage(out); } void DonkeyProtocol::getPending() { DonkeyMessage out(GetPending); sock.sendMessage(out); } void DonkeyProtocol::getSearches() { DonkeyMessage out(GetSearches); sock.sendMessage(out); } void DonkeyProtocol::getSearch(int search) { DonkeyMessage out(GetSearch); out.writeInt32(search); sock.sendMessage(out); } void DonkeyProtocol::startDownload(const QStringList &names, int num, bool force) { downloadstarted = true; DonkeyMessage out(Download_query); out.writeInt16(names.count()); for (int i = 0; i < (int)names.count(); i++) out.writeString(names[i]); out.writeInt32(num); out.writeInt8(force); sock.sendMessage(out); } void DonkeyProtocol::refreshShared() { DonkeyMessage out(RefreshUploadStats); sock.sendMessage(out); } void DonkeyProtocol::refreshFileInfo(int fileno) { DonkeyMessage out(GetFile_info); out.writeInt32(fileno); sock.sendMessage(out); } void DonkeyProtocol::refreshClientInfo(int clientno) { DonkeyMessage out(GetClient_info); out.writeInt32(clientno); sock.sendMessage(out); } uint DonkeyProtocol::connectedServerCount() { return connectedservers; } uint DonkeyProtocol::totalServerCount() { return servers.count(); } void DonkeyProtocol::searchForFriend(const QString& name) { DonkeyMessage out(FindFriend); out.writeString(name); sock.sendMessage(out); } void DonkeyProtocol::addClientFriend(int client) { DonkeyMessage out(AddClientFriend); out.writeInt32(client); sock.sendMessage(out); } void DonkeyProtocol::removeFriend(int client) { DonkeyMessage out(RemoveFriend); out.writeInt32(client); sock.sendMessage(out); } void DonkeyProtocol::removeAllFriends() { sock.sendMessage(DonkeyMessage(RemoveAllFriends)); } void DonkeyProtocol::connectFriend(int client) { DonkeyMessage out(ConnectFriend); out.writeInt32(client); sock.sendMessage(out); } const ResultInfo* DonkeyProtocol::findClientFile(int fileno) { return unmappedResults[fileno]; } const QMap& DonkeyProtocol::optionsList() { return options; } QString DonkeyProtocol::getOption(const QString& option) { return options.contains(option) ? options[option] : QString::null; } void DonkeyProtocol::setOption(const QString& option, const QString& value) { DonkeyMessage out(SetOption); out.writeString(option); out.writeString(value); sock.sendMessage(out); } void DonkeyProtocol::setOptions(const QMap& opts) { if (opts.count() < 1) return; DonkeyMessage out(SaveOptions_query); out.writeInt16( (int16) opts.count() ); for (QMap::ConstIterator it = opts.begin(); it != opts.end(); ++it) { out.writeString( it.key() ); out.writeString( it.data() ); } sock.sendMessage(out); } void DonkeyProtocol::enableNetwork(int nwno, bool enable) { Network* nw = networks[nwno]; if (! nw) return; DonkeyMessage out(EnableNetwork); out.writeInt32( (int32) nw->networkNo() ); out.writeInt8( (int8) (enable ? 1 : 0) ); sock.sendMessage(out); } const QValueList& DonkeyProtocol::sectionOptions() { return m_sectionOptions; } const QValueList& DonkeyProtocol::pluginOptions() { return m_pluginOptions; } void DonkeyProtocol::killCore() { sock.sendMessage(DonkeyMessage(KillServer)); } void DonkeyProtocol::sendPrivateMessage(int client, const QString& message) { DonkeyMessage out(MessageToClient); out.writeInt32(client); out.writeString(message); sock.sendMessage(out); } const int DonkeyProtocol::coreProtocolVersion() { return coreProto; } RoomInfo* DonkeyProtocol::findRoomNo(int roomno) { return rooms[roomno]; } void DonkeyProtocol::setRoomState(int roomno, RoomInfo::RoomState state) { kdDebug() << "DonkeyProtocol::setRoomState() roomno=" << roomno << " state=" << state << endl; DonkeyMessage out(SetRoomState); out.writeInt32(roomno); out.writeInt32(state); sock.sendMessage(out); } void DonkeyProtocol::renameFile(int fileno, const QString& name) { DonkeyMessage out(RenameFile); out.writeInt32(fileno); out.writeString(name); sock.sendMessage(out); } void DonkeyProtocol::updateUploaders() { DonkeyMessage out(GetUploaders); sock.sendMessage(out); } void DonkeyProtocol::connectClient(int client) { DonkeyMessage out(ConnectClient); out.writeInt32(client); sock.sendMessage(out); } void DonkeyProtocol::disconnectClient(int client) { DonkeyMessage out(DisconnectClient); out.writeInt32(client); sock.sendMessage(out); } void DonkeyProtocol::sendNetworkMessage(int network, const QString& msg) { DonkeyMessage out(NetworkMessage); out.writeInt32(network); out.writeString(msg); sock.sendMessage(out); } void DonkeyProtocol::interestedInSources(bool interested) { DonkeyMessage out(InterestedInSources); out.writeBool(interested); sock.sendMessage(out); } void DonkeyProtocol::requestVersion() { DonkeyMessage out(GetVersion); sock.sendMessage(out); } void DonkeyProtocol::renameServer(int id, const QString& name) { DonkeyMessage out(ServerRename); out.writeInt32(id); out.writeString(name); sock.sendMessage(out); } void DonkeyProtocol::setServerPreferred(int id, bool preferred) { DonkeyMessage out(ServerSetPreferred); out.writeInt32(id); out.writeBool(preferred); sock.sendMessage(out); } #include "donkeyprotocol.moc"