/* This file is part of dc_qt. dc_qt 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. dc_qt 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 dc_qt; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "dctc_hub.h" #include "dc_parse.h" #include "dctc_connection.h" #include "file_transfer.h" #include "util.h" #include "dc_settings.h" #include "debugdlg.h" #include "mainwdgt.h" #include #include #include #include #include using namespace std; const char* USER_CMD = "USER "; const char* OP_CMD = "OP "; const char* USER_PLUS_CMD = "USER+"; const char* USER_MINUS_CMD = "USER-"; const char* USER_INFO_CMD = "UINFO"; const char* HUB_MINUS_CMD = "HUB- "; const char* HUB_PLUS_CMD = "HUB+ "; const char* ERR_CMD = "ERR "; const char* DL_START_CMD = "$DL+ "; const char* DL_DONE_CMD = "$DL- "; const char* DL_RUN_CMD = "$DL= "; const char* DL_ABORT_CMD = "$DL# "; const char* DL_DEQUEUE_CMD = "$DL~ "; const char* UL_START_CMD = "$UL+ "; const char* UL_ABORT_CMD = "$UL# "; const char* UL_DONE_CMD = "$UL- "; const char* UL_RUN_CMD = "$UL= "; const char* UL_INFO_CMD = "$ULST"; const char* SEARCH_RESULT = "SREST"; const char* CHAT_CMD = "CHAT "; const char* PRIVCHAT_CMD = "PRIV "; const char* ASTRT_CMD = "ASTRT"; const char* GDL_CONTENT_CMD = "GLSTC"; const char* GDL_CONTENT_START = "GLSTB"; const char* GDL_CONTENT_END = "GLSTE"; const char* HUB_NAME_CMD = "HUBNM"; const char* FLST_RECV_CMD = "LSCCH"; const char* PASWD_CMD = "PASWD"; const char* VAR_CMD = "VAR "; const char* PRGBR_CMD = "PRGBR"; const char* XFERR_CMD = "XFERR"; // running transfer const char* XFERQ_CMD = "XFERQ"; // queued transfer const char* BXFER_CMD = "BXFER"; // begin list of transfers const char* EXFER_CMD = "EXFER"; // end list of transfers const char* RFRSH_CMD = "RFRSH"; // a transfer has ended dctc_connection* dctc_hub::master = 0; typedef pair intPair; void dctc_hub::killMaster() { if(master) { master->hubdisconnect(); delete master; } } dctc_hub::dctc_hub(QObject *parent, const char* name) : QObject(parent, name) { connection = new dctc_connection(parent, QString("conn-") + name); QObject::connect(connection, SIGNAL(dctc_data(const QString&)), SLOT(dc_string(const QString &))); QObject::connect(connection, SIGNAL(hub_died()), SLOT(connection_died())); incoming_info = false; incoming_xfer_info = false; userListSent = false; } dctc_hub::~dctc_hub() { delete connection; // delete master; } int dctc_hub::hubconnect(const QString &ip,const QString &pwd, int pid) { int ret = connection->hubconnect(ip, pwd, pid); if (ret != CONNECT_SUCCESS) { debugWin->print("Could not connect to hub"); return ret; } hubip = ip; if(master) QObject::connect(master, SIGNAL(dctc_data(const QString&)), this, SLOT(masterString(const QString &))); return CONNECT_SUCCESS; } int dctc_hub::hubconnect(const QString &ip,const QString &pwd, const QString &profile) { debugWin->print("Using profile to connect: " + profile); int ret = connection->hubconnect(ip, pwd, 0,profile); if (ret != CONNECT_SUCCESS) return ret; hubip = ip; if(master) QObject::connect(master, SIGNAL(dctc_data(const QString&)), this, SLOT(masterString(const QString &))); return CONNECT_SUCCESS; } void dctc_hub::connectToMaster() { debugWin->print("Connecting to master..."); master = new dctc_connection(0,"masterconnection"); int ret = master->connectToMaster(); if(ret!=CONNECT_SUCCESS) { delete master; master = 0; debugWin->print("Connect to master failed. Socket file exist but connect failed."); return; } QObject::connect(master, SIGNAL(dctc_data(const QString&)), this, SLOT(masterString(const QString &))); doPostInit(); } void dctc_hub::doPostInit() { QString xbl(""); xbl = settings.get_setting("ul_rate_limit"); if (!xbl.isEmpty() && xbl!="0") send_command("/UBL " + QString::number( xbl.toInt()*2)); xbl = settings.get_setting("dl_rate_limit"); if (!xbl.isEmpty() && xbl!="0") send_command("/DBL " + xbl); } void dctc_hub::hubdisconnect() { if (!connection) return; connection->hubdisconnect(); // QObject::disconnect(this, SLOT(dc_string(const QString &))); // QObject::disconnect(this, SLOT(connection_died())); QObject::disconnect(master,0,this,0); } void dctc_hub::search_for(const QString &pattern, bool multiHub) { send_command("/SRCH " + pattern); } // given a string received from the text client, emit the right signal // so that the window can be updated correctly void dctc_hub::parse_dctc_string(const QString &str) { QString command_type(dctc_command_type(str)); // Special case 1 if(command_type != UL_INFO_CMD) debugWin->log(str + "\n"); // Special case 2 if(!userListSent && command_type != USER_CMD /*&&command_type!=OP_CMD*/ && userList.size() > 0) { debugWin->print("Emitting userlistarrived with " + QString::number(userList.size())); emit userListArrived(userList); userListSent = true; } if(command_type == UL_INFO_CMD) { // An upload is running, do something clever. This one is sent by dctc a lot of times // during the upload. dc_parse p(dctc_command_data(str),':',true); // p.remove_quotes(); // TODO: emit only sometimes? check cpu usage due to massive signaling emit uploadUpdated(p.source()); } else if( command_type == HUB_NAME_CMD ) { dc_parse p(dctc_command_data(str),'|'); p.remove_quotes(); emit hub_name(p.get_str(0)); } else if (command_type == USER_CMD /*|| command_type == OP_CMD*/) { dc_parse p(dctc_command_data(str),'|'); p.remove_quotes(); userList+=p.get_str(0); //emit user_added(p.get_str(0), true); } else if( command_type == OP_CMD ) { dc_parse p(dctc_command_data(str),'|'); p.remove_quotes(); emit userIsOp(p.get_str(0)); } else if (command_type == USER_PLUS_CMD && userListSent) { dc_parse p(dctc_command_data(str),'|'); p.remove_quotes(); emit user_added(p.get_str(0)); } else if (command_type == USER_MINUS_CMD) { dc_parse p(dctc_command_data(str),'|'); p.remove_quotes(); emit user_removed(p.get_str(0)); } else if (command_type == HUB_MINUS_CMD) { dc_parse p(dctc_command_data(str),'|'); p.remove_quotes(); debugWin->print("HUB-: " + p.get_str(0)); emit hubDisconnect(DISCONNECT_HUB); } else if (command_type == HUB_PLUS_CMD) { emit hubReached(); } else if (command_type == USER_INFO_CMD) { parse_uinfo(dctc_command_data(str)); } else if (command_type == SEARCH_RESULT) { QString file, user, size, slot, hubname; parse_srest(dctc_command_data(str), user, file, size, slot, hubname); emit search_file(user, file, size, slot, hubname); } else if (command_type == CHAT_CMD) { dc_parse p(dctc_command_data(str), '|'); p.remove_quotes(); emit chat_msg(p.get_str(0)); } else if (command_type == PRIVCHAT_CMD) { // input is on form aaa|bbb. aaa is the user you are chatting with, // bbb is the message (a little simplified, but it will do). dc_parse p(dctc_command_data(str),'|'); p.remove_quotes(); emit privchat_msg( p.get_str(0), p.get_str(1) ); } else if (command_type == ERR_CMD) { //if(dctc_command_data(str).contains("Use /GDLATTACH to attach")) //{ //emit unattachedGDL(lastGDLName); //} debugWin->print("Error: " + dctc_command_data(str)); } else if(command_type == ASTRT_CMD) { // Something has started, notify the transfer list if it's a XDL /* -- I don't know what this does and why so I'm removing it. dc_parse p(dctc_command_data(str),'|'); p.remove_quotes(); if(p.get_str(0) == "/XDL") { emit new_transfer( p.get_str(1).toInt(), p.get_str(2) ); // GDL id and nick send_command_master("/GDLLST"); } else debugWin->print("FIXME: Unsupported ASTRT detected"); */ } else if(command_type == UL_RUN_CMD) { // An upload has started and is running. dc_parse p(dctc_command_data(str),'|',true); // p.remove_quotes(); emit uploadAdded(p.source()); /* int id = p.get_str(0).toInt(); const QString nick = p.get_str(1); QString filename = p.get_str(2); int index = filename.findRev('/'); filename.remove(0,index+1); emit new_upload(id,nick,filename); */ } else if(command_type == UL_DONE_CMD || command_type == UL_ABORT_CMD) { dc_parse p(dctc_command_data(str),'|'); cerr << str << "\n"; fflush(stderr); p.remove_quotes(); QString filename = p.get_str(1); /* int index = filename.findRev('/'); if(index>=0) filename.remove(0,index+1); else debugWin->print("ULDONE FIS"); */ emit uploadClosed(p.get_str(0), filename); } else if(command_type == GDL_CONTENT_START) { incoming_info=true; } else if(command_type == GDL_CONTENT_END) { incoming_info=false; emit gdlListEnd(); } else if(command_type == GDL_CONTENT_CMD) { dc_parse p(dctc_command_data(str), '|'); p.remove_quotes(); emit gdlUpdated(p.source()); // parseGDLContent( str ); } else if(command_type == FLST_RECV_CMD) { dc_parse p(dctc_command_data(str),'|'); p.remove_quotes(); QString user = p.get_str(0); emit userFileList(user); } else if(command_type == PASWD_CMD) { emit passwordRequired(); } else if (command_type == DL_DONE_CMD || command_type == DL_ABORT_CMD) { /* dc_parse p(dctc_command_data(str), '|'); p.remove_quotes(); emit uploadClosed(p.get_str(0), p.get_str(1)); */ } // // estrato adding some more stuff here // else if(command_type == DL_START_CMD) { debugWin->print("### DL STARTING ### : " + str); } else if(command_type == DL_RUN_CMD) { debugWin->print("### DL RUNNING ### : " + str); } else if(command_type == DL_DEQUEUE_CMD) { debugWin->print("### DL DE-QUEUED ### : " + str); } else if(command_type == RFRSH_CMD) { // debugWin->print("### TRANSFER ENDED; REFRESH ### : " + str); } // end of estrato-added stuff else if(command_type=PRGBR_CMD) { dc_parse p(dctc_command_data(str),'|'); p.remove_quotes(); QStringList l; for(int i=2;iprint("dctc_hub: Unsupported command: " + str); return; } } void dctc_hub::parse_uinfo(const QString &str) { //cerr << str << "\n"; int a = 0; while(str[a]!='"') a++; a+=2; int l = 1; while(str[a+l]!=' ') l++; QString nick = str.mid(a,l); a+=l+1;l=1; // Second string is number of shared bytes. while(str[a+l]!=' ') l++; QString share(str.mid(a,l)); a+=l+1;l=1; // Third string: type of connection while(str[a+l]!=' ') l++; QString cnx = str.mid(a,l); a+=l+1;l=1; // Fourth string is on the form [(XX)...] where XX is a flag. int flag; while(str[a+l]!=' ') l++; QString fs = str.mid(a,l); sscanf(fs,"(%d)",&flag); bool away = (flag & 0x2)==1; a+=l;l=0;while(str[a]==' ') a++; // Fifth string: user email enclosed in '', could be empty. QString email = QString::null; if(str[a]=='\'') { a++; while(str[a+l]!='\'') l++; email = str.mid(a,l); a+=l+1;while(str[a]==' ') a++; } l=1; QString desc = QString::null; if(str[a]!='|') { while(str[a+l]!='|') l++; desc = str.mid(a,l); } emit user_info(nick,share,cnx,email,desc,away); } // return the text before the ']' in the text client string QString dctc_hub::dctc_command_type(const QString &str) { QString ret; for (unsigned int i = 0; i < str.length() && str[i] != ']'; i++) ret += str[i]; // string debug(ret.latin1()); return ret; } // return the data after the ']' in the text client string // may need to be used in conjuction with a dc_parse QString dctc_hub::dctc_command_data(const QString &str) { QString ret; bool data = false; for (unsigned int i = 0; i < str.length(); i++) { if (data) { ret += str[i]; continue; } if (!data && str[i] == ']') { data = true; } } // string debug(ret.latin1()); return ret; } void dctc_hub::send_command(const QString &command) { // if(connectionStatus==1) // { debugWin->print("dctc_hub: Sending command " + command + "\n"); // if (connection) connection->send_command(command); // if(master) master->send_command(command); // } // else // debugWin->print("Rejecting command " + command + ", connection is not ready.\n"); } void dctc_hub::send_command_master(const QString &cmd) { if (master) { if (cmd != "/GDLLST") debugWin->print("dctc_hub: Sending command to master " + cmd + "\n"); master->send_command(cmd); } else { if (cmd != "/GDLLST") debugWin->print("dctc_hub: Rejecting command to master - no connection exists!"); } } void dctc_hub::getUserInfos() { debugWin->print("Getting user infos " + QString::number(userList.size())); int i = 1; for(QStringList::Iterator it = userList.begin();it!=userList.end();++it) { if(i%100==0) usleep(10000); i++; connection->send_command("/UINFO " + *it); } } void dctc_hub::dc_string(const QString &dc) { parse_dctc_string(dc); } void dctc_hub::masterString(const QString &dc) { // cerr << dc << "\n"; QString command_type(dctc_command_type(dc)); if(command_type == GDL_CONTENT_START || command_type == GDL_CONTENT_END || command_type == GDL_CONTENT_CMD) parse_dctc_string(dc); } void dctc_hub::get_uinfo(const QString &user) { send_command("/UINFO " + user); } void dctc_hub::get_user_list(const QString &user) { send_command("/LS " + user); } void dctc_hub::parse_file(const QString &str, QString &user, QString &file, QString &size) { dc_parse p(str, '|'); p.remove_quotes(); user = p.get_str(0); file = p.get_str(1); size = p.get_str(2); } void dctc_hub::parse_srest(const QString &str, QString &user, QString &file, QString &size, QString &slot, QString& hubname) { dc_parse p(str, '|'); p.remove_quotes(); user = p.get_str(0); file = p.get_str(1); size = p.get_str(2); slot = p.get_str(3); hubname = p.get_str(4); } void dctc_hub::get_hub_name() { send_command("/HUBNAME"); } void dctc_hub::get_file(int gdlid,const QString &user, const QString &file,const QString &targetFile, unsigned long int size) { QString cmd; cmd = "/GDLNEW " + QString::number(gdlid) + "|" + QString::number(size) + "|" + targetFile; debugWin->print(cmd+"\n"); send_command_master(cmd); cmd = "/GDLADD " + QString::number(gdlid) + "|" + user + "|" + file + "|" + QString::number(size); debugWin->print(cmd+"\n"); send_command_master(cmd); } void dctc_hub::addSource(int gdlid,const QString& user, const QString& file, unsigned long int size) { QString cmd = "/GDLADD " + QString::number(gdlid) + "|" + user + "|" + file + "|" + QString::number(size); send_command_master(cmd); } void dctc_hub::parseGDLContent( const QString &str ) { dc_parse p(str,'|'); p.remove_quotes(); emit gdlUpdated(p.source()); /* int gdlId = p.get_str(0).toInt(); QString fname = p.get_str(1); int totSize = p.get_str(2).toInt(); int recSize = p.get_str(4).toInt(); int recLast10 = p.get_str(6).toInt(); // number of bytes received last 10 secs // ddd: zero or more entries QString users = ""; QString status = ""; int i = 10; // ddd entries, 10 == 1st in list while (p.get_str(i)!="") { // while(1) { // if(p.get_str(i)=="") break; dc_parse q(p.get_str(i),'$'); users += q.get_str(0) + '|'; status += q.get_str(3) + '|'; i++; } users.truncate( users.length() - 1 ); status.truncate( status.length() - 1 ); // parse 'eee': completed segments. /estrato QString complete_files = ""; QString complete_ranges = ""; // eee: zero or more entries, i+1 == 1st in list while(p.get_str(++i)!="") { dc_parse q(p.get_str(i),'$'); complete_files += q.get_str(0) + '|'; complete_ranges += q.get_str(3) + '|'; } complete_files.truncate( complete_files.length() - 1 ); complete_ranges.truncate( complete_ranges.length() - 1 ); QString s; s.sprintf("emitting transfer_info: gdl-id=%d, fname=%s, size=%d, users=%s, status=%s\n" "Completed ranges (not handled): files \"%s\", ranges \"%s\"\n", gdlId, fname.latin1(), totSize, users.latin1(), status.latin1(), complete_files.latin1(), complete_ranges.latin1()); debugWin->print( s ); emit transfer_info( gdlId, fname, totSize, recSize, recLast10,users,status ); */ } void dctc_hub::parse_xferr(const QString &str) { /* dc_parse p(str, '|'); p.remove_quotes(); int transfer_id = p.get_str(0).toInt(); QString nick = p.get_str(1); QString type = p.get_str(2); if (type == "XDL") { int gdlId = p.get_str(3).toInt(); // ok, here must send to transfer dlg // need transfer id to be able to kill individual sources // Check if it's in the idMap // map::iterator it = idMap.find(gdlId); // if( it == idMap.end() ) // idMap.insert( intPair(gdlId,transfer_id) ); } */ } void dctc_hub::send_chatmsg(const QString &msg) { send_command("/CHAT " + msg); } void dctc_hub::send_privmsg(const QString &msg,const QString &nick) { send_command("/PRIV *" + nick + "*" + msg); } void dctc_hub::cancel_transfer(unsigned int id) { send_command_master("/GDLEND " + QString::number(id)); } void dctc_hub::delete_gdl(unsigned int id,const QString& nick,const QString& file) { send_command_master("/GDLDEL " + QString::number(id) + "|" + nick + "|" + file); } void dctc_hub::connection_died() { emit hubDisconnect(DISCONNECT_DIED); } void dctc_hub::request_dlist() { if(!incoming_info) { send_command_master("/GDLLST"); // send_command("/GDLLIST"); } } void dctc_hub::attachFile(const QString& name) { send_command_master("/GDLATTACH " + name); } void dctc_hub::detachId(const unsigned int id) { send_command_master(QString("/GDLDETACH %1").arg(id)); } void dctc_hub::retryTransfer(const QString& nick) { send_command_master("/WAKEUGDL " + nick); } void dctc_hub::sendPassword(const QString& p) { send_command("/PASSWD " + p); } void dctc_hub::reshare() { QStringList shares = QStringList::split(";",settings.get_setting("shares")); for ( QStringList::Iterator it = shares.begin(); it != shares.end(); ++it ) { send_command("/UNSHARE " + (*it)); send_command("/SHARE " + (*it)); } send_command("/RESHARE"); } /// This function is incorrect and should be regarded as a temporary solution. void dctc_hub::updateDescription() { if(settings.get_setting("desc_tag")=="dcgui") { int numConnections = MainWdgt::getInstance().getNumConnections(); QString mode; /// Fucks upp if the user changed this value while connected. if( settings.get_setting("passive_mode")=="true") mode = "P"; else mode="A"; QString sl(settings.get_setting("slots")); QString limit(settings.get_setting("ul_rate_limit")); QString tag = ""; send_command("/DESC " + settings.get_setting("description")+" "+tag); } }