/* museekd - The Museek daemon * * 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 #include #include #include #define MULOG_DOMAIN "museekd.MD" #include #include using std::vector; using std::set; using std::string; using std::wstring; using std::map; using std::cerr; using std::endl; Museekd::Museekd(const string& config, const string& version) : Museek(), mVersion(version), mKicked(false), mHaveBuddyShares(false), mReconnectTime(15), mConfigFile(config), mConfig(mConfigFile), mStatus(0), mPrivilegeBuddies(false), mOnlyBuddies(false), mTrustedUploads(false), mJoined(false), mDontSaveDownloads(false), mSaveDownloads(false), mLastSave(0), mPonged(false), mPingTime(0) { CT("Museekd"); } bool Museekd::load_config() { mConfig = Muconf(mConfigFile); string base; int ix1 = mConfigFile.rfind('.'), ix2 = mConfigFile.rfind('/'); if(ix1 > ix2) base = mConfigFile.substr(0, ix1 + 1); else base = mConfigFile + "."; mConfig["interfaces"]["password"]; if(! mConfig.hasDomain("interfaces.bind")) { mConfig["interfaces.bind"]["localhost:2240"]; #ifdef HAVE_SYS_UN_H # ifdef HAVE_PWD_H struct passwd *pw = getpwuid(getuid()); if(pw) mConfig["interfaces.bind"][string("/tmp/museekd.") + pw->pw_name]; # endif #endif } // added logging defaults (darrik@mythofbutterfly.com) if (! mConfig["logging"]["output"]) { // console output mConfig["logging"]["output"] = 0; } if (! mConfig["logging"]["syslog_facility"]) { // LOG_LOCAL6 facility (see syslog.h) mConfig["logging"]["syslog_facility"] = 176; } if (! mConfig["logging"]["syslog_priority"]) { // LOG_DEBUG priority (see syslog.h) mConfig["logging"]["syslog_priority"] = 7; } // end logging defaults if(! mConfig["shares"]["database"]) mConfig["shares"]["database"] = base + "shares"; if(! mConfig["buddy.shares"]["database"]) mConfig["buddy.shares"]["database"] = base + "buddyshares"; if(! mConfig["transfers"]["downloads"]) mConfig["transfers"]["downloads"] = base + "downloads"; if(! mConfig["server"]["host"]) mConfig["server"]["host"] = "server.slsknet.org"; if(! mConfig["server"]["port"]) mConfig["server"]["port"] = 2240; mConfig["server"]["username"]; mConfig["server"]["password"]; if(! mConfig["clients"]["connectmode"]) mConfig["clients"]["connectmode"] = "passive"; if(! mConfig["clients.bind"]["first"]) mConfig["clients.bind"]["first"] = "2234"; if(! mConfig["clients.bind"]["last"]) mConfig["clients.bind"]["last"] = "2240"; if(! mConfig["encoding"]["network"]) mConfig["encoding"]["network"] = "utf-8"; if(! mConfig["encoding"]["filesystem"]) mConfig["encoding"]["filesystem"] = "latin1"; if(! mConfig["transfers"]["upload_slots"]) mConfig["transfers"]["upload_slots"] = 1; if(! mConfig["transfers"]["privilege_buddies"]) mConfig["transfers"]["privilege_buddies"] = true; if(! mConfig["transfers"]["user_warnings"]) mConfig["transfers"]["user_warnings"] = true; if(! mConfig["transfers"]["only_buddies"]) mConfig["transfers"]["only_buddies"] = false; if(! mConfig["transfers"]["trusting_uploads"]) mConfig["transfers"]["trusting_uploads"] = false; if(! mConfig["transfers"]["have_buddy_shares"]) mConfig["transfers"]["have_buddy_shares"] = false; mConfig["transfers"]["download-dir"]; mConfig["transfers"]["incomplete-dir"]; mConfig["encoding.rooms"]; mConfig["encoding.users"]; mConfig["buddies"]; mConfig["banned"]; mConfig["ignored"]; mConfig["trusted"]; mConfig["userinfo"]["text"]; if(! mConfig["userinfo"]["image"]) mConfig["userinfo"]["image"] = base + "image"; mConfig["interests.like"]; mConfig["interests.hate"]; mConfig["tickers"]; mConfig["default-ticker"]["ticker"]; mConfig.store(); bool incomplete = false; if(! mConfig["interfaces"]["password"]) { cerr << "FATAL: Interface password missing in " << mConfigFile << endl; incomplete = true; } if(! mConfig["server"]["username"]) { cerr << "FATAL: Username missing in " << mConfigFile << endl; incomplete = true; } if(! mConfig["server"]["password"]) { cerr << "FATAL: Password missing in " << mConfigFile << endl; incomplete = true; } if(! mConfig["transfers"]["download-dir"]) { cerr << "FATAL: Download dir missing in " << mConfigFile << endl; incomplete = true; } return ! incomplete; } void Museekd::init() { // initial output sink for mulog DEBUG("changing logging output to %d",mConfig["logging"]["output"].asUint()); mulog.setSyslogFacility(mConfig["logging"]["syslog_facility"].asUint()); mulog.setSyslogPriority(mConfig["logging"]["syslog_priority"].asUint()); mulog.setOutput(mConfig["logging"]["output"].asUint()); set_port_range(mConfig["clients.bind"]["first"].asUint(), mConfig["clients.bind"]["last"].asUint()); Museek::init(); load_downloads(); init_iface_listeners(); load_shares(); load_buddy_shares(); init_buddies(); mHaveBuddyShares = mConfig["transfers"]["have_buddy_shares"].asBool(); set_have_buddy_shares(mHaveBuddyShares); mTrustedUploads = mConfig["transfers"]["trusting_uploads"].asBool(); mPrivilegeBuddies = mConfig["transfers"]["privilege_buddies"].asBool(); mOnlyBuddies = mConfig["transfers"]["only_buddies"].asBool(); mUserWarnings = mConfig["transfers"]["user_warnings"].asBool(); mu_set_user_warnings(mUserWarnings); set_user_warnings(mUserWarnings); set_only_buddies(mOnlyBuddies); mu_set_only_buddies(mOnlyBuddies); update_buddies(); set_server(mConfig["server"]["host"], mConfig["server"]["port"].asUint()); set_username(mConfig["server"]["username"]); set_password(mConfig["server"]["password"]); if(mConfig["clients"]["connectmode"] == string("active")) set_connect_mode(CM_Active); else set_connect_mode(CM_Passive); set_upload_slots(mConfig["transfers"]["upload_slots"].asInt()); mUserinfo = mRecoder->decode_utf8(mConfig["userinfo"]["text"]); set_iface_password(mConfig["interfaces"]["password"]); FILE *f = fopen(mConfig["userinfo"]["image"], "r"); if(f) { vector tmpimg; int read; unsigned char buf[8192]; while((read = fread(buf, 1, 8192, f))) { for(int i = 0; i < read; ++i) tmpimg.push_back(buf[i]); } fclose(f); DEBUG("loaded userimage, %i bytes", tmpimg.size()); set_userpic(tmpimg); } else perror("cannot load userinfo image: "); vector autojoin = mConfig["autojoin"].keys(); vector::const_iterator it = autojoin.begin(); for(; it != autojoin.end(); ++it) { mJoinedRooms[*it]; mTickers[*it]; } } void Museekd::load_shares() { mShares->load(mConfig["shares"]["database"], "normal"); } void Museekd::load_buddy_shares() { mBuddyShares->load(mConfig["buddy.shares"]["database"], "buddy"); } void Museekd::init_recoder() { mRecoder = new Recoder(mConfig["encoding"]["filesystem"], mConfig["encoding"]["network"]); map codings = mConfig["encoding.users"]; map::iterator it = codings.begin(); for(; it != codings.end(); ++it) mRecoder->set_user((*it).first, (*it).second); codings = mConfig["encoding.rooms"]; for(it = codings.begin(); it != codings.end(); ++it) mRecoder->set_room((*it).first, (*it).second); } void Museekd::init_transfer_manager() { Museek::init_transfer_manager(); wstring temp_dir, download_dir = mRecoder->decode_utf8(mConfig["transfers"]["download-dir"]); if(! mConfig["transfers"]["incomplete-dir"]) temp_dir = download_dir; else temp_dir = mRecoder->decode_utf8(mConfig["transfers"]["incomplete-dir"]); if(download_dir[download_dir.size() - 1] != '/') download_dir += '/'; if(temp_dir[temp_dir.size() - 1] != '/') temp_dir += '/'; mTransferManager->set_download_dir(download_dir); mTransferManager->set_temp_dir(temp_dir); vector banned = mConfig["banned"].keys(); vector::iterator it = banned.begin(); for(; it != banned.end(); ++it) ban(*it); vector trusted = mConfig["trusted"].keys(); vector::iterator tit = trusted.begin(); for(; tit != trusted.end(); ++tit) trust(*tit); } void Museekd::init_iface_listeners() { StringMap ifaces = mConfig["interfaces.bind"]; StringMap::const_iterator it = ifaces.begin(); for(; it != ifaces.end(); ++it) { IfaceListener* listener = new IfaceListener(this, (*it).first); if(listener->get_error() == ERR_NONE) add(listener); } } void Museekd::init_buddies() { mBuddies = new Buddies(this); map buddies = mConfig["buddies"]; map::const_iterator it = buddies.begin(); for(; it != buddies.end(); ++it) mBuddies->add((*it).first); } static char challengemap[] = "0123456789abcdef"; string Museekd::challenge() { string r; for(int i = 0; i < 64; i++) r += challengemap[rand() % 16]; return r; } void Museekd::new_iface(IfaceConnection* conn) { mIfaces.push_back(conn); add(conn); conn->challenge(4, challenge()); } void Museekd::remove_iface(IfaceConnection* conn) { vector::iterator it; it = find(mIfaces.begin(), mIfaces.end(), conn); mIfaces.erase(it); vector searches; map::const_iterator s_it = mSearches.begin(); for(; s_it != mSearches.end(); ++s_it) if((*s_it).second == conn) searches.push_back((*s_it).first); vector::const_iterator _s_it = searches.begin(); for(; _s_it != searches.end(); ++_s_it) mSearches.erase(*_s_it); } #define ALL_IFACES(code) \ { vector::iterator if_it = mIfaces.begin(); \ for(; if_it != mIfaces.end(); ++if_it) { \ (*if_it)->code; } \ } #define ALL_IFACES_EX(conn, code) \ { vector::iterator if_it = mIfaces.begin(); \ for(; if_it != mIfaces.end(); ++if_it) \ if(*if_it != conn) \ (*if_it)->code; \ } void Museekd::cb_iface_ping(IfaceConnection* conn, uint32 id) { conn->ping(id); } void Museekd::cb_iface_login(IfaceConnection* conn, const string& algorithm, const string& chresponse) { string ch = conn->get_challenge() + mIfacePassword; unsigned char digest[32]; uint digest_len = 0; if(algorithm == "SHA1") { shaBlock((unsigned char*)ch.data(), ch.size(), digest); digest_len = 20; } else if(algorithm == "SHA256") { sha256Block((unsigned char*)ch.data(), ch.size(), digest); digest_len = 32; } else if(algorithm == "MD5") { md5Block((unsigned char*)ch.data(), ch.size(), digest); digest_len = 16; } else { conn->login_reply(false, "INVHASH", challenge()); return; } char hexdigest[65]; hexDigest(digest, digest_len, hexdigest); if(chresponse != hexdigest) { conn->login_reply(false, "INVPASS", challenge()); return; } conn->login_reply(true, string(), mIfacePassword); conn->server_state(logged_in(), mUsername); conn->config_state(mConfig); conn->room_state(mRoomList, mJoinedRooms, mRecoder->utf8_tickermap(mTickers)); conn->transfer_state(mTransferManager->uploads(), mTransferManager->downloads()); if(mLoggedIn) { conn->status_set(mPeerManager->get_peer(mUsername)->status() & 1); vector buddies = *mBuddies; vector::const_iterator it = buddies.begin(); for(; it != buddies.end(); ++it) { Peer* peer = mPeerManager->get_peer(*it); if(peer->have_exists()) conn->peer_exists(*it, peer->exists()); if(peer->have_status()) conn->peer_status(*it, peer->status()); if(peer->have_stats()) conn->peer_stats(*it, peer->avgspeed(), peer->downloadnum(), peer->files(), peer->dirs()); } vector::const_iterator itt = mTrusted.begin(); for(; itt != mTrusted.end(); ++itt) { Peer* peer = mPeerManager->get_peer(*itt); if(peer->have_exists()) conn->peer_exists(*itt, peer->exists()); if(peer->have_status()) conn->peer_status(*itt, peer->status()); if(peer->have_stats()) conn->peer_stats(*itt, peer->avgspeed(), peer->downloadnum(), peer->files(), peer->dirs()); } if(conn->mask() & EM_PRIVATE) { vector::iterator it = mPrivateMessages.begin(); for(; it != mPrivateMessages.end(); ++it) { conn->private_message(0, (*it).timestamp + (mPonged ? mPingTime : 0), (*it).user, mRecoder->encode_utf8((*it).message)); server_ack_private((*it).ticket); } mPrivateMessages.clear(); } string _msg = ("Museek Daemon Version: "+ mVersion ); conn->status_message(0, _msg ); } } void Museekd::cb_iface_check_privileges(IfaceConnection*) { server_check_privileges(); } void Museekd::cb_iface_set_status(IfaceConnection *conn, uint32 status) { server_set_status(status ? 1 : 2); } void Museekd::cb_iface_config_set(IfaceConnection* conn, const string& domain, const string& key, const string& value) { mConfig[domain][key] = value; mConfig.store(); // added logging config change (darrik@mythofbutterfly.com) if (domain == "logging") { if (key == "output") { if (value == "1") { mulog.setOutput(1); } else { mulog.setOutput(0); } } else if (key == "syslog_facility") { mulog.setSyslogFacility(atoi(value.data())); } else if (key == "syslog_priority") { mulog.setSyslogPriority(atoi(value.data())); } // end logging config change } else if(domain == "buddies") { ALL_IFACES(config_set(domain, key, value)); mBuddies->add(key); if(Peer* peer = mPeerManager->get_peer(key, false)) { if(peer->have_exists()) ALL_IFACES(peer_exists(key, peer->exists())); if(peer->have_status()) ALL_IFACES(peer_status(key, peer->status())); if(peer->have_stats()) ALL_IFACES(peer_stats(key, peer->avgspeed(), peer->downloadnum(), peer->files(), peer->dirs())); } return; } else if(domain == "trusted") { trust(key); } else if(domain == "encoding.users") mRecoder->set_user(key, value); else if(domain == "encoding.rooms") mRecoder->set_room(key, value); else if(domain == "banned") ban(key); else if(domain == "transfers") { if(key == "upload_slots") { set_upload_slots(mConfig[domain][key].asInt()); mTransferManager->check_uploads(); } else if(key == "privilege_buddies") { set_privilege_buddies(mConfig[domain][key].asBool()); } else if(key == "user_warnings") { set_user_warnings(mConfig[domain][key].asBool()); } else if(key == "only_buddies") { set_only_buddies(mConfig[domain][key].asBool()); mu_set_only_buddies(mConfig[domain][key].asBool()); } else if(key == "trusting_uploads") { set_trusting_uploads(mConfig[domain][key].asBool()); } else if(key == "have_buddy_shares") { mHaveBuddyShares = mConfig[domain][key].asBool(); set_have_buddy_shares(mHaveBuddyShares); } } else if(domain == "clients" && key == "connectmode") { if (value == "active") set_connect_mode(CM_Active); else if (value == "passive") set_connect_mode(CM_Passive); } else if(domain == "userinfo" && key == "text") mUserinfo = mRecoder->decode_utf8(value); ALL_IFACES(config_set(domain, key, value)); } void Museekd::cb_iface_config_remove(IfaceConnection* conn, const string& domain, const string& key) { mConfig[domain].remove(key); mConfig.store(); if(domain == "buddies") mBuddies->del(key); else if(domain == "encoding.users") mRecoder->unset_user(key); else if(domain == "encoding.rooms") mRecoder->unset_room(key); else if(domain == "banned") unban(key); else if(domain == "trusted") untrust(key); ALL_IFACES(config_remove(domain, key)); } void Museekd::cb_iface_config_set_user_image(IfaceConnection*, const vector& data) { set_userpic(data); FILE *f = fopen(mConfig["userinfo"]["image"], "w"); if(f) { char *buf = new char[data.size()]; vector::const_iterator it, end = data.end(); int i = 0; for(it = data.begin(); it != end; ++it) buf[i++] = *it; fwrite(buf, 1, data.size(), f); fclose(f); delete [] buf; } } void Museekd::cb_iface_peer_exists(IfaceConnection* conn, const string& user) { Peer* peer = mPeerManager->get_peer(user); if(peer->have_exists()) { conn->peer_exists(user, peer->exists()); } else { peer->subscribe(); } } void Museekd::cb_iface_peer_status(IfaceConnection* conn, const string& user) { Peer* peer = mPeerManager->get_peer(user); if(peer->have_status()) { conn->peer_status(user, peer->status()); } else { server_get_peer_status(user); } } void Museekd::cb_iface_peer_stats(IfaceConnection* conn, const string& user) { Peer* peer = mPeerManager->get_peer(user); if(peer->have_stats()) { conn->peer_stats(user, peer->avgspeed(), peer->downloadnum(), peer->files(), peer->dirs()); } else { server_get_peer_stats(user); } } void Museekd::cb_iface_peer_address(IfaceConnection* conn, const string& user) { Peer* peer = mPeerManager->get_peer(user); // if(peer->have_address()) { // conn->peer_address(user, peer->ip(), peer->port()); // } else { server_get_peer_address(user); // } } void Museekd::cb_iface_info(IfaceConnection* conn, const string& user) { if(user == mUsername) { mPeerManager->get_peer(user)->connection()->local_userinfo_request(); server_get_peer_interests(user); } else { mPeerManager->get_peer(user)->connection()->info(); server_get_peer_interests(user); } } void Museekd::cb_iface_shares(IfaceConnection* conn, const string& user) { if(user == mUsername) { mPeerManager->get_peer(user)->connection()->local_shares_request(); } else { mPeerManager->get_peer(user)->connection()->shares(); } } void Museekd::cb_iface_give_privileges(IfaceConnection* conn, const string& user, uint32 days) { server_give_privileges(user, days); } void Museekd::cb_iface_room_list(IfaceConnection* coon) { server_room_list(); } void Museekd::cb_iface_get_global_recommendations(IfaceConnection* coon) { server_get_global_recommendations(); } void Museekd::cb_iface_get_recommendations(IfaceConnection* coon) { server_get_recommendations(); } void Museekd::cb_iface_get_similar_users(IfaceConnection* coon) { server_get_similar_users(); } void Museekd::cb_iface_get_item_recommendations(IfaceConnection* coon, const string& item) { server_get_item_recommendations(item); } void Museekd::cb_iface_get_item_similar_users(IfaceConnection* coon, const string& item) { server_get_item_similar_users(item); } void Museekd::cb_iface_private(IfaceConnection* conn, const string& user, const string& message) { server_send_private(user, mRecoder->decode_utf8(message)); ALL_IFACES_EX(conn, private_message(1, time(NULL), user, message)); } void Museekd::cb_iface_join_room(IfaceConnection* conn, const string& room) { map::iterator it = mJoinedRooms.find(room); if(it != mJoinedRooms.end()) return; if(mJoined) server_join_room(room); else { mJoinedRooms[room]; mTickers[room]; ALL_IFACES(joined_room(room, mJoinedRooms[room])); } } void Museekd::cb_iface_leave_room(IfaceConnection* conn, const string& room) { map::iterator it = mJoinedRooms.find(room); if(it == mJoinedRooms.end()) return; if(mJoined) server_leave_room(room); else { mJoinedRooms.erase(it); mTickers.erase(room); ALL_IFACES(left_room(room)); } } void Museekd::cb_iface_remove_interest(IfaceConnection* conn, const string& interest) { server_remove_interest(interest); mConfig["interests.like"].remove(interest); mConfig.store(); ALL_IFACES(config_remove("interests.like", interest)); } void Museekd::cb_iface_remove_hated_interest(IfaceConnection* conn, const string& interest) { server_remove_hated_interest(interest); mConfig["interests.hate"].remove(interest); mConfig.store(); ALL_IFACES(config_remove("interests.hate", interest)); } void Museekd::cb_iface_add_interest(IfaceConnection* conn, const string& interest) { server_add_interest(interest); mConfig["interests.like"][interest]; mConfig.store(); ALL_IFACES(config_set("interests.like", interest, "")); } void Museekd::cb_iface_add_hated_interest(IfaceConnection* conn, const string& interest) { server_add_hated_interest(interest); mConfig["interests.hate"][interest]; mConfig.store(); ALL_IFACES(config_set("interests.hate", interest, "")); } void Museekd::cb_server_remove_interest(const string& interest) { } void Museekd::cb_server_remove_hated_interest(const string& interest) { } void Museekd::cb_server_add_interest(const string& interest) { } void Museekd::cb_server_add_hated_interest(const string& interest) { } void Museekd::cb_peer_transfer_finished(const wstring& path, const string& user) { string _path = mRecoder->encode_utf8(path); string _msg = ("Finished downloading "+ _path +" from "+ user ); ALL_IFACES(status_message(1, _msg )); } void Museekd::cb_peer_banned(const string& user) { string _msg = ("Refused to send shares to: "+ user ); ALL_IFACES(status_message(1, _msg )); peer_banned(user); } void Museekd::cb_peer_upload_blocked(const string& user) { string _msg = ("Refused to accept file from non-trusted user: "+ user ); ALL_IFACES(status_message(1, _msg )); peer_upload_blocked(user); } void Museekd::cb_peer_sent_buddy_shares(const string& user) { string _msg = ("Buddy Shares sent to: "+ user ); ALL_IFACES(status_message(1, _msg )); } void Museekd::cb_peer_sent_normal_shares(const string& user) { string _msg = ("Normal Shares sent to: "+ user ); ALL_IFACES(status_message(1, _msg )); } void Museekd::cb_peer_sent_user_info(const string& user) { string _msg = ("User Info sent to: "+ user ); ALL_IFACES(status_message(1, _msg )); } void Museekd::cb_server_global_message(const string& message) { string _msg = ("Global Message: "+ message ); ALL_IFACES(status_message(0, _msg )); } void Museekd::msg_server_privileged_users(uint32 _size) { string _msg = string("Privileged users: " + itos(_size) ); ALL_IFACES(status_message(0, _msg)); } void Museekd::cb_iface_say_room(IfaceConnection* conn, const string& room, const string& message) { if(mJoinedRooms.find(room) == mJoinedRooms.end() || message.empty()) return; server_say_room(room, mRecoder->decode_utf8(message)); } void Museekd::cb_iface_room_ticker_set(IfaceConnection* conn, const string& room, const string& message) { if(mJoinedRooms.find(room) == mJoinedRooms.end()) return; server_set_ticker(room, mRecoder->decode_utf8(message)); } void Museekd::cb_iface_user_search(IfaceConnection* conn, const string& user, const string& query) { uint32 ticket = token(); mSearches[ticket] = conn; conn->search(query, ticket); wstring wquery = mRecoder->decode_utf8(query); server_user_search(user, ticket, wquery); } void Museekd::cb_iface_wishlist_search(IfaceConnection* conn, const string& query) { uint32 ticket = token(); mSearches[ticket] = conn; conn->search(query, ticket); wstring wquery = mRecoder->decode_utf8(query); server_wishlist_search(ticket, wquery); } void Museekd::cb_iface_search(IfaceConnection* conn, uint32 type, const string& query) { uint32 ticket = token(); mSearches[ticket] = conn; conn->search(query, ticket); wstring wquery = mRecoder->decode_utf8(query); if(type == 0) { server_search(ticket, wquery); } else if(type == 1) { vector buddies = *mBuddies; vector::iterator it, end = buddies.end(); for(it = buddies.begin(); it != end; ++it) if (mConfig["server"]["username"] != *it) server_user_search(*it, ticket, wquery); //mPeerManager->get_peer(*it)->connection()->search(ticket, wquery); } else if (type == 2) { DEBUG ("Room search : %s", query.c_str ()); set room_users; map::iterator it, end = mJoinedRooms.end (); for (it = mJoinedRooms.begin() ; it != end ; ++it) { DEBUG ("Room search : %s", (*it).first.c_str()); server_room_search( (*it).first, ticket, wquery); // DEBUG ("Adding users from room %s...", (*it).first.c_str ()); // RoomData rdata = (*it).second; // // map::iterator it2, end2 = rdata.end (); // // for (it2 = rdata.begin () ; it2 != end2 ; ++it2) // { // UserData udata = (*it2).second; // // if (mConfig["server"]["username"] != (*it2).first) // room_users.insert (room_users.begin(), (*it2).first); // } } // // set::iterator it3, end3 = room_users.end(); // DEBUG ("Sending messages to the %d users...", room_users.size ()); // for(it3 = room_users.begin() ; it3 != end3 ; ++it3) // mPeerManager->get_peer(*it3)->connection()->search(ticket, wquery); } } void Museekd::cb_iface_terminate(IfaceConnection* conn, const uint32 ticket) { map::const_iterator it = mSearches.find(ticket); if(it == mSearches.end() || (*it).second != conn) return; mSearches.erase(ticket); } void Museekd::cb_iface_transfer_update(IfaceConnection* conn, const string& user, const string& path) { mPeerManager->get_peer(user)->connection()->place_in_queue(mRecoder->decode_utf8(path)); } void Museekd::cb_iface_transfer_delete(IfaceConnection* conn, bool upload, const string& user, const string& path) { Transfer* transfer; if(upload) { transfer = mPeerManager->get_peer(user)->upload(mRecoder->decode_utf8(path)); } else { transfer = mPeerManager->get_peer(user)->download(mRecoder->decode_utf8(path)); } if(transfer) { transfer->set_state(TS_Aborted); delete transfer; } } void Museekd::cb_iface_upload_file(IfaceConnection* conn, const string& user, const string& path) { Peer *peer = mPeerManager->get_peer(user, true); if(peer) { mPeerManager->get_peer(user)->connection()->upload_notification(); // const string pa = str_replace(path, '/', '\\'); mTransferManager->send_upload(user, mRecoder->decode_utf8(path)); } } void Museekd::cb_iface_download_file(IfaceConnection* conn, const string& user, const string& path) { if(! (user.empty() || path.empty())) mTransferManager->new_download(user, mRecoder->decode_utf8(path), wstring(), wstring(), 0); } void Museekd::cb_iface_download_file_to(IfaceConnection* conn, const string& user, const string& path, const string& dpath) { if(! (user.empty() || path.empty())) mTransferManager->new_download(user, mRecoder->decode_utf8(path), mRecoder->decode_utf8(dpath), wstring(), 0); } void Museekd::cb_iface_download_folder(IfaceConnection* conn, const string& user, const string& folder) { if(! (user.empty() || folder.empty())) mPeerManager->get_peer(user)->connection()->folder_contents(mRecoder->decode_utf8(folder)); } void Museekd::cb_iface_transfer_abort(IfaceConnection*, bool upload, const string& user, const string& path) { Peer* peer = mPeerManager->get_peer(user, false); if(peer) { if(upload) peer->abort_upload(mRecoder->decode_utf8(path)); else peer->abort_download(mRecoder->decode_utf8(path)); } } void Museekd::reconnect() { struct itimerval ival; ival.it_value.tv_sec = mReconnectTime; ival.it_interval.tv_sec = 0; ival.it_interval.tv_usec = ival.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &ival, NULL); } void Museekd::cb_iface_disconnect_server(IfaceConnection*) { mKicked = true; server_disconnect(); } void Museekd::cb_iface_connect_server(IfaceConnection*) { do_reconnect(); } void Museekd::cb_iface_reload_shares(IfaceConnection*) { DEBUG("reloading shares..."); load_shares(); DEBUG("reloading buddy shares..."); load_buddy_shares(); ALL_IFACES(status_message(0, "Reloaded Shares.." )); } void Museekd::do_reconnect() { mKicked = true; server_disconnect(); DEBUG("Reconnecting: reloading server config"); set_server(mConfig["server"]["host"], mConfig["server"]["port"].asUint()); set_username(mConfig["server"]["username"]); set_password(mConfig["server"]["password"]); server_connect(); mKicked = false; } void Museekd::cb_server_disconnected() { Museek::cb_server_disconnected(); /* NOTE: The private messages haven't been acked yet, we will get them again when we re-connect */ mPrivateMessages.clear(); map::iterator it = mJoinedRooms.begin(); for(; it != mJoinedRooms.end(); ++it) (*it).second.clear(); map::iterator tit = mTickers.begin(); for(; tit != mTickers.end(); ++tit) (*tit).second.clear(); mJoined = false; ALL_IFACES(server_state(false, "")); mReconnectTime = 15; if (! mKicked) { DEBUG("*sniff* server disconnected us, trying again in %i seconds", mReconnectTime); ALL_IFACES(status_message(0, "Server disconnected us, reconnecting in a bit.")); reconnect(); } else ALL_IFACES(status_message(0, "Server disconnected us, not reconnecting.")); } void Museekd::cb_server_kicked() { Museek::cb_server_kicked(); mKicked = true; DEBUG("Forced the server to disconnect us, giving up"); ALL_IFACES(status_message(0, "Disconnected from Server, not reconnecting.")); } void Museekd::cb_server_cannot_connect() { Museek::cb_server_cannot_connect(); DEBUG("cannot connect to server, trying again in %i seconds", mReconnectTime); ALL_IFACES(status_message(0, "Could not connect to server, trying again in a bit.")); reconnect(); if(mReconnectTime < 60) mReconnectTime *= 2; } void Museekd::cb_server_cannot_login() { Museek::cb_server_cannot_login(); DEBUG("timeout while logging in to the server", mReconnectTime); ALL_IFACES(status_message(0, "Timed out while logging into the server.")); /* don't call reconnect here, since we're disconnected after we get here, cb_server_disconnected() will do that for us */ } void Museekd::cb_server_cannot_resolve() { Museek::cb_server_cannot_resolve(); if(mReconnectTime < 60) mReconnectTime *= 2; DEBUG("cannot resolve server, trying again in %i seconds", mReconnectTime); ALL_IFACES(status_message(0, "cannot resolve server, trying again in a bit")); reconnect(); } void Museekd::cb_server_logged_in(bool success, const string& message) { Museek::cb_server_logged_in(success, message); if(success) { mPonged = false; mPingTime = time(0); ALL_IFACES(server_state(true, mUsername)); ALL_IFACES(status_message(0, "Logged into Server as "+ mUsername)); ALL_IFACES(status_message(0, message)); server_send_private(mUsername, wstring(L"\001")); vector interests_like = mConfig["interests.like"].keys(); vector interests_hate = mConfig["interests.hate"].keys(); vector::const_iterator lit = interests_like.begin(); for(; lit != interests_like.end(); ++lit) { server_add_interest(*lit); } vector::const_iterator hit = interests_hate.begin(); for(; hit != interests_hate.end(); ++hit) { server_add_hated_interest(*hit); } } } void Museekd::cb_server_privileges_left(uint32 time_left) { ALL_IFACES(privileges_left(time_left)); } void Museekd::cb_server_peer_status(const string& user, uint32 status) { Museek::cb_server_peer_status(user, status); map::iterator r_it = mJoinedRooms.begin(); for(; r_it != mJoinedRooms.end(); ++r_it) { RoomData::iterator u_it = (*r_it).second.find(user); if(u_it == (*r_it).second.end()) continue; (*u_it).second.status = status; } ALL_IFACES(peer_status(user, status)); if(user == mUsername) ALL_IFACES(status_set(status & 1)); } void Museekd::cb_server_peer_stats(const string& user, uint32 avgspeed, uint32 downloadnum, uint32 files, uint32 dirs) { Museek::cb_server_peer_stats(user, avgspeed, downloadnum, files, dirs); map::iterator r_it = mJoinedRooms.begin(); for(; r_it != mJoinedRooms.end(); ++r_it) { RoomData::iterator u_it = (*r_it).second.find(user); if(u_it == (*r_it).second.end()) continue; (*u_it).second.avgspeed = avgspeed; (*u_it).second.downloadnum = downloadnum; (*u_it).second.files = files; (*u_it).second.dirs = dirs; } ALL_IFACES(peer_stats(user, avgspeed, downloadnum, files, dirs)); } void Museekd::cb_server_peer_address(const string& user, const string& ip, uint32 port) { Museek::cb_server_peer_address(user, ip, port); ALL_IFACES(peer_address(user, ip, port)); } void Museekd::cb_server_private(uint32 msg_id, uint32 timestamp, const string& user, const wstring& message) { if(! mPonged && user == mUsername && message == wstring(L"\001")) { mPonged = true; mPingTime -= timestamp; server_ack_private(msg_id); vector ifaces; vector::iterator iface = mIfaces.begin(); for(; iface != mIfaces.end(); ++iface) if((*iface)->mask() & EM_PRIVATE) ifaces.push_back(*iface); if(ifaces.empty()) return; vector::iterator it, end = mPrivateMessages.end(); for(it = mPrivateMessages.begin(); it != end; ++it) { for(iface = ifaces.begin(); iface != ifaces.end(); ++iface) (*iface)->private_message(0, (*it).timestamp + mPingTime, (*it).user, mRecoder->encode_utf8((*it).message)); server_ack_private((*it).ticket); } return; } if(mConfig["ignored"].hasKey(user)) { server_ack_private(msg_id); return; } bool sent = false; if(mPonged) { vector::iterator it = mIfaces.begin(); for(; it != mIfaces.end(); ++it) { if((*it)->mask() & EM_PRIVATE) { sent = true; (*it)->private_message(0, timestamp + mPingTime, user, mRecoder->encode_utf8(message)); } } } if(sent) { server_ack_private(msg_id); } else { PrivateMessage pm; pm.ticket = msg_id; pm.timestamp = timestamp; pm.user = user; pm.message = message; mPrivateMessages.push_back(pm); } } void Museekd::cb_server_room_list(const RoomList& rooms) { mRoomList = rooms; if(! mJoined) { map::iterator it = mJoinedRooms.begin(); for(; it != mJoinedRooms.end(); ++it) { (*it).second.clear(); server_join_room((*it).first); // if (mConfig["tickers"][(*it).first] ) { // wstring tricky = mRecoder->decode_utf8(mConfig["tickers"][(*it).first]); // server_set_ticker((*it).first.c_str(), tricky); // } else { // wstring tricky = mRecoder->decode_utf8(mConfig["default-ticker"]["ticker"]); // server_set_ticker((*it).first.c_str(), tricky); // } } mJoined = true; } ALL_IFACES(room_list(mRoomList)); } void Museekd::cb_server_get_global_recommendations(const Recommendations& recommendations) { mRecommendations = recommendations; ALL_IFACES(get_global_recommendations(mRecommendations)); } void Museekd::cb_server_get_recommendations(const string& interest, const Recommendations& recommendations) { mRecommendations = recommendations; ALL_IFACES(get_recommendations(mRecommendations)); } void Museekd::cb_server_get_similar_users(const SimilarUsers& similarusers) { mSimilarUsers = similarusers; ALL_IFACES(get_similar_users(mSimilarUsers)); } void Museekd::cb_server_get_item_similar_users(const string& item, const SimilarUsers& similarusers) { mSimilarUsers = similarusers; ALL_IFACES(get_item_similar_users(item, mSimilarUsers)); } void Museekd::cb_server_get_item_recommendations(const string& item, const Recommendations& recommendations) { mRecommendations = recommendations; ALL_IFACES(get_item_recommendations(item, mRecommendations)); } void Museekd::cb_server_joined_room(const string& room, const RoomData& users) { mJoinedRooms[room] = users; mTickers[room].clear(); ALL_IFACES(joined_room(room, users)); if ( mConfig["tickers"][room]) { wstring tricky = mRecoder->decode_utf8(mConfig["tickers"][room]); if (tricky.empty()) { wstring tricky = mRecoder->decode_utf8(mConfig["default-ticker"]["ticker"]); server_set_ticker(room.c_str(), tricky); } else server_set_ticker(room.c_str(), tricky); } else { wstring tricky = mRecoder->decode_utf8(mConfig["default-ticker"]["ticker"]); server_set_ticker(room.c_str(), tricky); } } void Museekd::cb_server_left_room(const string& room) { if(mJoinedRooms.find(room) == mJoinedRooms.end()) return; mJoinedRooms.erase(room); mTickers.erase(room); ALL_IFACES(left_room(room)); } void Museekd::cb_server_say_room(const string& room, const string& user, const wstring& message) { if(! mConfig["ignored"].hasKey(user)) { string _msg = mRecoder->encode_utf8(message); ALL_IFACES(say_room(room, user, _msg)); } } void Museekd::cb_server_user_joined_room(const string& room, const string& user, const UserData& userdata) { map::iterator rit = mJoinedRooms.find(room); if(rit == mJoinedRooms.end()) return; RoomData::const_iterator uit = (*rit).second.find(user); if(uit != (*rit).second.end()) return; (*rit).second[user] = userdata; ALL_IFACES(user_joined_room(room, user, userdata)); } void Museekd::cb_server_user_left_room(const string& room, const string& user) { map::iterator rit = mJoinedRooms.find(room); if(rit == mJoinedRooms.end()) return; RoomData::const_iterator uit = (*rit).second.find(user); if(uit == (*rit).second.end()) return; (*rit).second.erase(user); mTickers[room].erase(user); ALL_IFACES(user_left_room(room, user)); } void Museekd::cb_server_room_tickers(const string& room, const WTickers& tickers) { if(mTickers.find(room) == mTickers.end()) return; mTickers[room] = tickers; ALL_IFACES(room_tickers(room, mRecoder->utf8_tickers(tickers))); } void Museekd::cb_server_add_room_ticker(const string& room, const string& user, const wstring& message) { if(message.empty()) { cb_server_del_room_ticker(room, user); return; } map::iterator it = mTickers.find(room); if(it == mTickers.end()) return; (*it).second[user] = message; ALL_IFACES(room_ticker_set(room, user, mRecoder->encode_utf8(message))); } void Museekd::cb_server_del_room_ticker(const string& room, const string& user) { map::iterator it = mTickers.find(room); if(it == mTickers.end()) return; WTickers::iterator tit = (*it).second.find(user); if(tit == (*it).second.end()) return; (*it).second.erase(tit); ALL_IFACES(room_ticker_set(room, user, "")); } void Museekd::cb_peer_shares(const string& user, const WShares& shares) { ALL_IFACES(shares(user, mRecoder->utf8_shares(shares))); } void Museekd::cb_peer_info(const string& user, const wstring& info, const vector& pic, uint32 totalupl, uint32 queuelen, bool slotfree) { ALL_IFACES(info(user, mRecoder->encode_utf8(info), pic, totalupl, queuelen, slotfree)); } void Museekd::cb_peer_results(uint32 ticket, const string& user, const WFolder& results, uint32 avgspeed, uint32 queuelen, bool slotfree) { map::const_iterator it = mSearches.find(ticket); if(it == mSearches.end()) { DEBUG("couldn't find search ticket %u", ticket); } else { DEBUG("found search ticket %u", ticket); (*it).second->results(ticket, user, mRecoder->utf8_folder(results), avgspeed, queuelen, slotfree); } } void Museekd::cb_peer_folder_contents(const string& user, const wstring& dir, const WShares& contents) { wstring path = dir; if(path[path.size() - 1] == '\\') path = path.substr(0, path.size() - 1); path = transfer_manager()->download_dir() + path.substr(path.rfind('\\') + 1); DEBUG("folder: %s", mRecoder->encode_filesystem(path).c_str()); WShares::const_iterator it = contents.begin(); for(; it != contents.end(); ++it) { wstring subdir = (*it).first; if(! subdir.size()) subdir = '\\'; if(subdir[subdir.size()-1] != '\\') subdir += '\\'; wstring subpath = path; subpath += '/'; if(subdir.size() > dir.size()) { subpath += str_replace(subdir.substr(dir.size()), '\\', '/'); } DEBUG(" - %s", mRecoder->encode_filesystem(subpath).c_str()); WFolder::const_iterator fit = (*it).second.begin(); for(; fit != (*it).second.end(); ++fit) { DEBUG(" - %s", mRecoder->encode_filesystem(subpath + (*fit).first).c_str()); transfer_manager()->new_download(user, subdir + (*fit).first, subpath + (*fit).first, wstring(), (*fit).second.size); } } } void Museekd::cb_transfer_update(const Transfer* transfer) { ALL_IFACES(transfer_update(transfer)); if(! mDontSaveDownloads && transfer->direction() == Transfer::Download && transfer->state() != TS_Transferring) { mLastSave = time(0); mSaveDownloads = true; } } void Museekd::cb_transfer_delete(const Transfer* transfer) { ALL_IFACES(transfer_delete(transfer)); if(! mDontSaveDownloads && transfer->direction() == Transfer::Download) { mLastSave = time(0); mSaveDownloads = true; } } static inline int write_int(int fd, uint32 i) { unsigned char d[4]; for(int j = 0; j < 4; j++) { d[j] = i & 0xff; i = i >> 8; } return write(fd, d, 4); } static inline int write_off(int fd, off_t i) { unsigned char d[8]; for(int j = 0; j < 8; j++) { d[j] = i & 0xff; i = i >> 8; } return write(fd, d, 8); } static inline int write_str(int fd, const string& str) { if(write_int(fd, str.size()) == -1) return -1; const char* d = str.data(); return write(fd, d, str.size()); } static inline int read_int(int fd, uint32* r) { unsigned char d[4]; *r = 0; if(read(fd, d, 4) == -1) return -1; for(uint32 j = 0; j < 4; j++) (*r) += d[j] << (j * 8); return 4; } static inline int read_off(int fd, off_t* r) { unsigned char d[8]; (*r) = 0; if(read(fd, d, 8) == -1) return -1; for(off_t j = 0; j < 8; j++) (*r) += d[j] << (j * 8); return 8; } static inline int read_str(int fd, string& r) { uint32 len; if(read_int(fd, &len) == -1) return -1; char d[len]; if(read(fd, d, len) == -1) return -1; r.append(d, len); return len + 4; } void Museekd::load_downloads() { int fd = open(mConfig["transfers"]["downloads"], 0); if(fd == -1) { DEBUG("Cannot load downloads. Bailing out"); return; } uint32 n; if(read_int(fd, &n) == -1) { DEBUG("Cannot load downloads. Bailing out"); return; } while(n) { uint32 state; off_t size; string user, path, localpath, temppath; if(read_int(fd, &state) == -1 || \ read_str(fd, user) == -1 || \ read_off(fd, &size) == -1 || \ read_str(fd, path) == -1 || \ read_str(fd, localpath) == -1 || \ read_str(fd, temppath) == -1) { DEBUG("Cannot load downloads. Bailing out"); return; } mDontSaveDownloads = true; Transfer* tr = mTransferManager->new_download(user, mRecoder->decode_utf8(path), mRecoder->decode_utf8(localpath), mRecoder->decode_utf8(temppath), size); if(state == 0) tr->set_state(TS_Aborted); mDontSaveDownloads = false; n--; } } void Museekd::save_downloads() { int fd = creat(mConfig["transfers"]["downloads"], S_IRUSR | S_IWUSR); if(fd == -1) { DEBUG("Cannot save downloads, trying again later"); return; } uint32 transfers = 0; vector::const_iterator it = mTransferManager->downloads().begin(); for(; it != mTransferManager->downloads().end(); ++it) if((*it)->state() != TS_Finished) transfers++; if(write_int(fd, transfers) == -1) { DEBUG("Cannot save downloads, trying again later. Leaving downloads file in corrupted state"); close(fd); return; } for(it = mTransferManager->downloads().begin(); it != mTransferManager->downloads().end(); ++it) { uint32 state; switch((*it)->state()) { case TS_Finished: continue; case TS_Aborted: state = 0; break; default: state = 1; break; } if(write_int(fd, state) == -1 || \ write_str(fd, (*it)->peer()->user()) == -1 || \ write_off(fd, (*it)->size()) == -1 || \ write_str(fd, (*it)->path_utf8()) == -1 || \ write_str(fd, mRecoder->encode_utf8((*it)->local_path())) == -1 || \ write_str(fd, mRecoder->encode_utf8((*it)->temp_path())) == -1) { DEBUG("Cannot save downloads, trying again later. Leaving downloads file in corrupted state"); close(fd); return; } } close(fd); mSaveDownloads = false; } bool Museekd::is_privileged(const string& user) { if((mOnlyBuddies || mPrivilegeBuddies) && mBuddies->has(user)) return true; else return Museek::is_privileged(user); } bool Museekd::is_buddied(const string& user) const { if( mBuddies->has(user)) return true; else return Museek::is_buddied(user); } bool Museekd::is_trusted(const string& user) const { if(mTrustedUploads ) return find(mTrusted.begin(), mTrusted.end(), user) != mTrusted.end(); else return false; } void Museekd::trust(const string& user) { if(find(mTrusted.begin(), mTrusted.end(), user) != mTrusted.end()) return; mTrusted.push_back(user); } void Museekd::untrust(const string& user) { vector::iterator it = find(mTrusted.begin(), mTrusted.end(), user); if(it != mTrusted.end()) mTrusted.erase(it); } void Museekd::ban(const string& user) { if(find(mBanned.begin(), mBanned.end(), user) != mBanned.end()) return; mBanned.push_back(user); Peer *peer = mPeerManager->get_peer(user, false); if(peer) mTransferManager->ban_user(peer); } void Museekd::unban(const string& user) { vector::iterator it = find(mBanned.begin(), mBanned.end(), user); if(it != mBanned.end()) mBanned.erase(it); } void Museekd::remove_receiving(const string& user) { vector::iterator it = find(mReceiving.begin(), mReceiving.end(), user); if(it != mReceiving.end()) mReceiving.erase(it); // remove_receiving(user); } void Museekd::add_receiving(const string& user) { DEBUG ("Add to Receiving list: %s", user.c_str ()); if(find(mReceiving.begin(), mReceiving.end(), user) != mReceiving.end()) return; mReceiving.push_back(user); } bool Museekd::is_receiving_shares(const string& user) const { return find(mReceiving.begin(), mReceiving.end(), user) != mReceiving.end(); } bool Museekd::is_banned(const string& user) const { if(mOnlyBuddies && ! mBuddies->has(user)) return true; else return find(mBanned.begin(), mBanned.end(), user) != mBanned.end(); } void Museekd::set_privilege_buddies(bool b) { if(mPrivilegeBuddies == b) return; mPrivilegeBuddies = b; update_buddies(); } void Museekd::set_user_warnings(bool b) { if(mUserWarnings == b) return; mUserWarnings = b; } void Museekd::set_only_buddies(bool b) { if(mOnlyBuddies == b) return; mOnlyBuddies = b; update_buddies(); } void Museekd::set_trusting_uploads(bool b) { if(mTrustedUploads == b) return; mTrustedUploads = b; } void Museekd::update_buddies() { map& peers = mPeerManager->peers(); map::iterator it, end = peers.end(); for(it = peers.begin(); it != end; ++it) { (*it).second->set_privileged(is_privileged((*it).first)); if(mOnlyBuddies && ! mBuddies->has((*it).first)) mTransferManager->ban_user((*it).second); } } void Museekd::cycle_callback() { Museek::cycle_callback(); time_t curtime = time(0); if(mSaveDownloads && curtime > mLastSave) { save_downloads(); mLastSave = curtime; } }