/* Museek - Museek's 'core' library * * Copyright (C) 2003-2004 Hyriand * * 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 #include #include #include #include #include #include #include #define MULOG_DOMAIN "Museek.PC" #include #include using std::string; using std::wstring; PeerConnection::PeerConnection(Peer* peer, uint32 token) : BaseConnection(4, "P", peer, token), mLocked(false) { CT("PeerConnection %s, %u", peer->user().c_str(), token); mUser = peer->user(); mMuseek = peer->manager()->museek(); } #ifdef PARSE # undef PARSE #endif #define PARSE(mtype) mtype s; s.parse_network_packet(message); void PeerConnection::process_message(uint32 code) { CT("process_message %u (%s)", code, peer()->user().c_str()); switch(code) { case 4: { // Recieved a Request for Shares List if( mMuseek->is_banned(mUser)) { mMuseek->cb_peer_banned(mUser); break; } if (mUser == mMuseek->username()) { DEBUG("you are attempting to browse yourself... or being spoofed, blocked"); break; } if (mMuseek->is_receiving_shares(mUser)) { DEBUG("already sent shared files list %s", mUser.c_str()); } else { // Unfinished receiving users list // mMuseek->add_receiving(mUser); if ( mMuseek->mBuddySharesHave && mMuseek->is_buddied(mUser)) { lock(); DEBUG("sending buddy shared files list %s", mUser.c_str()); PSharesReply r(mMuseek->buddyshares()->shares()); send(r); mMuseek->cb_peer_sent_buddy_shares(mUser); } else { lock(); DEBUG("sending normal shared files list %s", mUser.c_str()); PSharesReply r(mMuseek->shares()->shares()); send(r); mMuseek->cb_peer_sent_normal_shares(mUser); } } break; } case 5: { // Recieved a Shares List; Send Data to User Interfaces PARSE(PSharesReply) DEBUG("got shared file list %s with %u directories", mUser.c_str(), s.shares.size()); mMuseek->cb_peer_shares(mUser, mMuseek->recoder()->decode_shares(mUser, s.shares)); break; } case 8: { // Recieved a Search Request; Check shares for a match PARSE(PSearchRequest); DEBUG("peer search request from %s: %s", mUser.c_str(), s.query.c_str()); mMuseek->cb_peer_search(this, mUser, s.ticket, mMuseek->recoder()->decode_user(mUser, s.query)); break; } case 9: { // Recieved a Search Reply (Results); Send Data to User Interfaces PARSE(PSearchReply); DEBUG("search results %s, %i", mUser.c_str(), s.results.size()); if(! s.results.empty() or ! s.failed) mMuseek->cb_peer_results(s.ticket, mUser, mMuseek->recoder()->decode_folder(mUser, s.results), s.avgspeed, s.queuelen, s.slotfree); else if (s.failed) DEBUG("Parsing Search Reply failed"); /* yes, this is one of those evil-yet-functionalisms: */ if(inbuf.empty()) disconnect(); break; } case 15: { // A User Info Request was recieved; Craft a User Info Reply if(! mMuseek->is_banned(mUser)) { if (mUser == mMuseek->username()) { DEBUG("you are attempting to get your own userinfo... or being spoofed, blocked"); break; } DEBUG("sending user info to %s", mUser.c_str()); lock(); string newline = "\n"; string descr = mMuseek->recoder()->encode_network(mMuseek->userinfo()); std::string::size_type match = 0; while ((match = descr.find("\n", match)) != string::npos){ descr.insert(match, "\r"); match += 2; } PInfoReply r(descr, mMuseek->userpic(), mMuseek->upload_slots(), mMuseek->transfer_manager()->queue_length(mUser), mMuseek->transfer_manager()->slot_free()); send(r); mMuseek->cb_peer_sent_user_info(mUser); } break; } case 16: { // Recieved a User Info Reply; Send Data to User Interfaces PARSE(PInfoReply); DEBUG("got user info %s", mUser.c_str()); mMuseek->cb_peer_info(mUser, mMuseek->recoder()->decode_user(mUser, s.description), s.picture, s.totalupl, s.queuesize, s.slotfree); break; } case 36: { // Folder Contents Request; Check shares for this folder, and send contents if(! mMuseek->is_banned(mUser)) { PARSE(PFolderContentsRequest); if ( mMuseek->mBuddySharesHave && mMuseek->is_buddied(mUser)) DEBUG("got buddy folder contents request %s, %d", mUser.c_str(),s.dirs.size()); else DEBUG("got folder contents request %s, %d", mUser.c_str(),s.dirs.size()); Folders res; StringList::iterator it = s.dirs.begin(); for(; it != s.dirs.end(); ++it) { DEBUG("%s", (*it).c_str()); if(res.find(*it) != res.end()) continue; if ( mMuseek->mBuddySharesHave && mMuseek->is_buddied(mUser)) res[*it] = mMuseek->buddyshares()->folder_contents(*it); else res[*it] = mMuseek->shares()->folder_contents(*it); } PFolderContentsReply r(res); send(r); } break; } case 37: { // Recieved Folder Contents Reply; Try to download these files PARSE(PFolderContentsReply); DEBUG("got folder contents reply from %s <...> (%d)", mUser.c_str(), s.folders.size()); Folders::iterator it = s.folders.begin(); for(; it != s.folders.end(); ++it) mMuseek->cb_peer_folder_contents(mUser, mMuseek->recoder()->decode_user(mUser, (*it).first), mMuseek->recoder()->decode_shares(mUser, (*it).second)); break; } case 40: { PARSE(PTransferRequest); if (s.direction == 0) { // Recieved Upload Request; Craft Upload Reply PUploadReply r; DEBUG("request for upload %s %s %u", mUser.c_str(), s.filename.c_str(), s.ticket); if ( mUser == mMuseek->username() ) { r = PUploadReply(s.ticket, "Cannot Transfer to yourself"); } else if(mMuseek->is_banned(mUser)) { DEBUG("banned"); if (mMuseek->mBuddiesOnly) r = PUploadReply(s.ticket, "Sharing Only to List"); else r = PUploadReply(s.ticket, "Banned"); } else if(! mMuseek->shares()->is_shared(s.filename) && ! mMuseek->buddyshares()->is_shared(s.filename) ) { DEBUG("not shared"); r = PUploadReply(s.ticket, "File not shared"); } else if(mMuseek->mBuddySharesHave && mMuseek->buddyshares()->is_shared(s.filename) && ! mMuseek->shares()->is_shared(s.filename) && ! mMuseek->is_buddied(mUser)) { DEBUG("shared only in buddy shares, but user is not a buddy"); r = PUploadReply(s.ticket, "File not shared"); } else if( ! mMuseek->mBuddySharesHave && mMuseek->buddyshares()->is_shared(s.filename) && ! mMuseek->shares()->is_shared(s.filename) ) { DEBUG("shared in buddy shares, but buddy shares not enabled"); r = PUploadReply(s.ticket, "File not shared"); } else { DEBUG("shared"); wstring path = mMuseek->recoder()->decode_network(s.filename); Transfer* upload = mMuseek->transfer_manager()->new_upload(mUser, path); if(! mPeer->uploading() && mMuseek->transfer_manager()->slot_free()) { DEBUG("slot free"); if(! upload->start_upload(s.ticket)) { r = PUploadReply(s.ticket, "Remote file error"); DEBUG("Local file error"); } else { DEBUG("Initiating transfer"); r = PUploadReply(s.ticket, upload->size()); } } else { DEBUG("queued"); r = PUploadReply(s.ticket, "Queued"); } } send(r); } else if (s.direction == 1) { // Recieved Download Request; Craft Download Reply PDownloadReply r; DEBUG("request for download %s %s %u", mUser.c_str(), s.filename.c_str(), s.ticket); std::wstring fn = mMuseek->recoder()->decode_user(mUser, s.filename); std::string reason; bool allowed = false; if ( mUser == mMuseek->username() ) { reason = "Cannot Transfer to yourself"; r = PDownloadReply(s.ticket, allowed, reason); send(r); break; } Transfer* dl = peer()->download(fn); if(! dl && mMuseek->is_trusted(mUser)) dl = mMuseek->transfer_manager()->new_download(mUser, fn, wstring(), wstring(), s.filesize); if(dl) { allowed = dl->start_download(s.ticket, s.filesize); if(! allowed) reason = "Remote file error"; } else { reason = "Cancelled"; } r = PDownloadReply(s.ticket, allowed, reason); send(r); } break; } case 41: { PARSE(PTransferReply); Transfer* transfer = mPeer->upload(s.ticket); if(! transfer) transfer = mPeer->download(s.ticket); if(! transfer) { DEBUG("couldn't find transfers %u (%s)", s.ticket, mUser.c_str()); break; } if (transfer->direction() == Transfer::Upload) { DEBUG("upload transfer reply %s, %u, %d", mUser.c_str(), s.ticket, s.allowed); if(transfer->state() != TS_Initiating) { DEBUG("weirdness, expected state TS_Initiating, found %i", transfer->state()); break; } if(! s.allowed) { transfer->set_state(TS_Aborted); } else { transfer->start_upload(); } } else { DEBUG("download transfer reply %s %u", mUser.c_str(), s.ticket); if(s.allowed) { transfer->start_download(s.filesize); } else { DEBUG("download denied %s, %s", mUser.c_str(), s.reason.c_str()); transfer->invalidate_ticket(); if(s.reason == "Queued") { transfer->set_state(TS_Queued); } else { transfer->set_error(s.reason); } } } break; } case 42: { PARSE(PUploadPlacehold); DEBUG("Upload Placehold %s, %s", mUser.c_str(), s.filename.c_str()); break; } case 43: { PARSE(PQueueDownload); DEBUG("queue upload %s, %s", mUser.c_str(), s.filename.c_str()); if(mMuseek->is_banned(mUser)) { PQueueFailed r(s.filename, "Banned or Sharing Only to List"); send(r); } else if(! mMuseek->shares()->is_shared(s.filename)) { PQueueFailed r(s.filename, "File not shared"); send(r); } else { mMuseek->transfer_manager()->new_upload(mUser, mMuseek->recoder()->decode_network(s.filename)); } break; } case 44: { PARSE(PPlaceInQueueReply); DEBUG("place in queue %s, %s, %i", mUser.c_str(), s.filename.c_str(), s.place); mMuseek->transfer_manager()->set_place_in_queue(mUser, mMuseek->recoder()->decode_user(mUser, s.filename), s.place); break; } case 51: { PARSE(PPlaceInQueueRequest); PPlaceInQueueReply r(s.filename, 0); DEBUG("place in queue request %s, %s", mUser.c_str(), s.filename.c_str()); Transfer *t = mPeer->upload(mMuseek->recoder()->decode_network(s.filename)); if(t && t->state() == TS_Queued) r.place = mMuseek->transfer_manager()->queue_length(mUser, t); send(r); } case 46: { PARSE(PUploadFailed); DEBUG("got Upload Failed from %s, %s", mUser.c_str(), s.filename.c_str()); Transfer *transfer = mPeer->download(mMuseek->recoder()->decode_user(mUser, s.filename)); if(! transfer) { DEBUG("couldn't find transfer %s, %s", mUser.c_str(), s.filename.c_str()); break; } if((transfer->state() != TS_Queued) || (! transfer->auto_retry())) transfer->set_error("Upload failed"); else DEBUG("Retrying download"); break; } case 52: { PARSE(PUploadQueueNotification); DEBUG("got Upload Queue Notification from %s", mUser.c_str() ); if(! mMuseek->is_trusted(mUser)) { mMuseek->cb_peer_upload_blocked(mUser); } break; } default: BaseConnection::process_message(code); } } void PeerConnection::shares() { CT("shares (%s)", mUser.c_str()); lock(); PSharesRequest r; send(r); } void PeerConnection::info() { CT("info (%s)", mUser.c_str()); lock(); PInfoRequest r; send(r); } void PeerConnection::folder_contents(const wstring& folder) { CT("folder_contents %s (%s)", folder.c_str(), mUser.c_str()); lock(); string _folder = mMuseek->recoder()->encode_user(mUser, folder); if(! _folder.empty()) { PFolderContentsRequest r(_folder); send(r); } } void PeerConnection::folder_contents(const WStringList& folders) { CT("folder_contents %u (%s)", folders.size(), mUser.c_str()); lock(); StringList _folders = mMuseek->recoder()->encode_user_list(mUser, folders); if(! _folders.empty()) { PFolderContentsRequest r(_folders); send(r); } } void PeerConnection::search(uint32 ticket, const wstring& query) { CT("search %u, %s (%s)", ticket, query.c_str(), mUser.c_str()); string _query = mMuseek->recoder()->encode_user(mUser, query); if(_query.size() >= 3) { PSearchRequest r(ticket, _query); send(r); } } void PeerConnection::results(uint32 ticket, const Folder& results) { CT("results %u, %u (%s)", ticket, results.size(), mUser.c_str()); const string& me = mMuseek->username(); PSearchReply r(ticket, me, results, mMuseek->peer_manager()->get_peer(me)->avgspeed(), mMuseek->transfer_manager()->queue_length(mUser), mMuseek->transfer_manager()->slot_free()); send(r); } void PeerConnection::download(uint32 ticket, const wstring& path) { CT("download %s", path.c_str()); string _path = mMuseek->recoder()->encode_user(mUser, path); if(! _path.empty()) { PTransferRequest r(ticket, _path); send(r); } } void PeerConnection::upload(Transfer *transfer) { CT("upload"); string _path = mMuseek->recoder()->encode_network(transfer->path()); if(! _path.empty()) { PTransferRequest r(transfer->ticket(), _path, transfer->size()); send(r); } } void PeerConnection::upload_failed(const wstring& path) { CT("upload_failed %s", mPeer->manager()->museek()->recoder()->encode_filesystem(path).c_str()); PUploadFailed r(mMuseek->recoder()->encode_network(path)); send(r); } void PeerConnection::queue_failed(const wstring& path, const string& reason) { CT("queue_failed %s, %s", mPeer->manager()->museek()->recoder()->encode_filesystem(path).c_str(), reason.c_str()); PQueueFailed r(mMuseek->recoder()->encode_network(path), reason); send(r); } void PeerConnection::place_in_queue(const wstring& path) { CT("place_in_queue %s", mPeer->manager()->museek()->recoder()->encode_filesystem(path).c_str()); PPlaceInQueueRequest r(mMuseek->recoder()->encode_network(path)); send(r); } void PeerConnection::upload_notification() { CT("upload_notification %s", mUser.c_str()); PUploadQueueNotification r; send(r); } void PeerConnection::local_shares_request() { CT("local_shares_request %s", mUser.c_str()); if ( mMuseek->mBuddySharesHave && mMuseek->is_buddied(mUser)) { PSharesReply r(mMuseek->buddyshares()->shares()); send(r); } else { PSharesReply r(mMuseek->shares()->shares()); send(r); } } void PeerConnection::local_userinfo_request() { CT("local_userinfo_request %s", mUser.c_str()); string descr = mMuseek->recoder()->encode_network(mMuseek->userinfo()); std::string::size_type match = 0; while ((match = descr.find("\n", match)) != string::npos){ descr.insert(match, "\r"); match += 2; } PInfoReply r(descr, mMuseek->userpic(), mMuseek->upload_slots(), mMuseek->transfer_manager()->queue_length(mUser), mMuseek->transfer_manager()->slot_free()); send(r); }