/* 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. */ /* Copyright (C) 2002 Dario Abatianni Copyright (C) 2005 Ismail Donmez Copyright (C) 2005 Peter Simonsson Copyright (C) 2005 John Tapsell Copyright (C) 2005-2008 Eike Hein */ #include "outputfilter.h" #include "konversationapplication.h" #include "konversationmainwindow.h" #include "awaymanager.h" #include "ignore.h" #include "server.h" #include "irccharsets.h" #include "linkaddressbook/addressbook.h" #include "query.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Konversation { OutputFilter::OutputFilter(Server* server) : TQObject(server) { m_server = server; } OutputFilter::~OutputFilter() { } // replace all aliases in the string and return true if anything got replaced at all bool OutputFilter::replaceAliases(TQString& line) { TQStringList aliasList=Preferences::aliasList(); TQString cc(Preferences::commandChar()); // check if the line starts with a defined alias for(unsigned int index=0;index" as "%%" aliasReplace.replace("%\x01","%%"); // modify line line=aliasReplace; // return "replaced" return true; } } // for return false; } TQStringList OutputFilter::splitForEncoding(const TQString& inputLine, uint max) { uint sublen = 0; //The encoded length since the last split int charLength = 0; //the length of this char int lastBreakPoint = 0; //FIXME should we run this through the encoder first, checking with "canEncode"? TQString text = inputLine; // the text we'll send, currently in Unicode TQStringList finals; // The strings we're going to output TQString channelCodecName=Preferences::channelEncoding(m_server->getDisplayName(), destination); //Get the codec we're supposed to use. This must not fail. (not verified) TQTextCodec* codec; // I copied this bit straight out of Server::send if (channelCodecName.isEmpty()) { codec = m_server->getIdentity()->getCodec(); } else { codec = Konversation::IRCCharsets::self()->codecForName(channelCodecName); } Q_ASSERT(codec); int index = 0; while(text.length() > max) { // The most important bit - turn the current char into a TQCString so we can measure it TQCString ch = codec->fromUnicode(TQString(text[index])); charLength = ch.length(); // If adding this char puts us over the limit: if (charLength + sublen > max) { if(lastBreakPoint != 0) { finals.append(text.left(lastBreakPoint + 1)); text = text.mid(lastBreakPoint + 1); } else { finals.append(text.left(index)); text = text.mid(index); } lastBreakPoint = 0; sublen = 0; index = 0; } else if (text[index].isSpace() || text[index].isPunct()) { lastBreakPoint = index; } ++index; sublen += charLength; } if (!text.isEmpty()) { finals.append(text); } return finals; } OutputFilterResult OutputFilter::parse(const TQString& myNick,const TQString& originalLine,const TQString& name) { setCommandChar(); OutputFilterResult result; destination=name; TQString inputLine(originalLine); if(inputLine.isEmpty() || inputLine == "\n") return result; //Protect against nickserv auth being sent as a message on the off chance // someone didn't notice leading spaces { TQString testNickServ( inputLine.stripWhiteSpace() ); if(testNickServ.startsWith(commandChar+"nickserv", false) || testNickServ.startsWith(commandChar+"ns", false)) { inputLine = testNickServ; } } if(!Preferences::disableExpansion()) { // replace placeholders inputLine.replace("%%","%\x01"); // make sure to protect double %% inputLine.replace("%B","\x02"); // replace %B with bold char inputLine.replace("%C","\x03"); // replace %C with color char inputLine.replace("%G","\x07"); // replace %G with ASCII BEL 0x07 inputLine.replace("%I","\x09"); // replace %I with italics char inputLine.replace("%O","\x0f"); // replace %O with reset to default char inputLine.replace("%S","\x13"); // replace %S with strikethru char // inputLine.replace(TQRegExp("%?"),"\x15"); inputLine.replace("%R","\x16"); // replace %R with reverse char inputLine.replace("%U","\x1f"); // replace %U with underline char inputLine.replace("%\x01","%"); // restore double %% as single % } TQString line=inputLine.lower(); // Convert double command chars at the beginning to single ones if(line.startsWith(commandChar+commandChar) && !destination.isEmpty()) { inputLine=inputLine.mid(1); goto BYPASS_COMMAND_PARSING; } // Server command? else if(line.startsWith(commandChar)) { TQString command = inputLine.section(' ', 0, 0).mid(1).lower(); TQString parameter = inputLine.section(' ', 1); if (command !="topic") parameter = parameter.stripWhiteSpace(); if (command == "join") result = parseJoin(parameter); else if(command == "part") result = parsePart(parameter); else if(command == "leave") result = parsePart(parameter); else if(command == "quit") result = parseQuit(parameter); else if(command == "close") result = parseClose(parameter); else if(command == "notice") result = parseNotice(parameter); else if(command == "j") result = parseJoin(parameter); else if(command == "me") result = parseMe(parameter, destination); else if(command == "msg") result = parseMsg(myNick,parameter, false); else if(command == "m") result = parseMsg(myNick,parameter, false); else if(command == "smsg") result = parseSMsg(parameter); else if(command == "query") result = parseMsg(myNick,parameter, true); else if(command == "op") result = parseOp(parameter); else if(command == "deop") result = parseDeop(myNick,parameter); else if(command == "hop") result = parseHop(parameter); else if(command == "dehop") result = parseDehop(myNick,parameter); else if(command == "voice") result = parseVoice(parameter); else if(command == "unvoice") result = parseUnvoice(myNick,parameter); else if(command == "devoice") result = parseUnvoice(myNick,parameter); else if(command == "ctcp") result = parseCtcp(parameter); else if(command == "ping") result = parseCtcp(parameter.section(' ', 0, 0) + " ping"); else if(command == "kick") result = parseKick(parameter); else if(command == "topic") result = parseTopic(parameter); else if(command == "away") parseAway(parameter); else if(command == "unaway") parseBack(); else if(command == "back") parseBack(); else if(command == "invite") result = parseInvite(parameter); else if(command == "exec") result = parseExec(parameter); else if(command == "notify") result = parseNotify(parameter); else if(command == "oper") result = parseOper(myNick,parameter); else if(command == "ban") result = parseBan(parameter); else if(command == "unban") result = parseUnban(parameter); else if(command == "kickban") result = parseBan(parameter,true); else if(command == "ignore") result = parseIgnore(parameter); else if(command == "unignore") result = parseUnignore(parameter); else if(command == "quote") result = parseQuote(parameter); else if(command == "say") result = parseSay(parameter); else if(command == "list") result = parseList(parameter); else if(command == "names") result = parseNames(parameter); else if(command == "raw") result = parseRaw(parameter); else if(command == "dcc") result = parseDcc(parameter); else if(command == "konsole") parseKonsole(); else if(command == "aaway") KonversationApplication::instance()->getAwayManager()->requestAllAway(parameter); else if(command == "aunaway") KonversationApplication::instance()->getAwayManager()->requestAllUnaway(); else if(command == "aback") KonversationApplication::instance()->getAwayManager()->requestAllUnaway(); else if(command == "ame") result = parseAme(parameter); else if(command == "amsg") result = parseAmsg(parameter); else if(command == "omsg") result = parseOmsg(parameter); else if(command == "onotice") result = parseOnotice(parameter); else if(command == "server") parseServer(parameter); else if(command == "reconnect") emit reconnectServer(); else if(command == "disconnect") emit disconnectServer(); else if(command == "charset") result = parseCharset(parameter); else if(command == "encoding") result = parseCharset(parameter); else if(command == "setkey") result = parseSetKey(parameter); else if(command == "delkey") result = parseDelKey(parameter); else if(command == "showkey") result = parseShowKey(parameter); else if(command == "dns") result = parseDNS(parameter); else if(command == "kill") result = parseKill(parameter); else if(command == "queuetuner") result = parseShowTuner(parameter); // Forward unknown commands to server else { result.toServer = inputLine.mid(1); result.type = Message; } } // Ordinary message to channel/query? else if(!destination.isEmpty()) { BYPASS_COMMAND_PARSING: TQStringList outputList=splitForEncoding(inputLine, m_server->getPreLength("PRIVMSG", destination)); if (outputList.count() > 1) { result.output=TQString(); result.outputList=outputList; for ( TQStringList::Iterator it = outputList.begin(); it != outputList.end(); ++it ) { result.toServerList += "PRIVMSG " + destination + " :" + *it; } } else { result.output = inputLine; result.toServer = "PRIVMSG " + destination + " :" + inputLine; } result.type = Message; } // Eveything else goes to the server unchanged else { result.toServer = inputLine; result.output = inputLine; result.typeString = i18n("Raw"); result.type = Program; } return result; } OutputFilterResult OutputFilter::parseShowTuner(const TQString ¶meter) { KonversationApplication *konvApp = static_cast(TDEApplication::kApplication()); OutputFilterResult result; if(parameter.isEmpty() || parameter == "on") konvApp->showQueueTuner(true); else if(parameter == "off") konvApp->showQueueTuner(false); else result = usage(i18n("Usage: %1queuetuner [on | off]").arg(commandChar)); return result; } OutputFilterResult OutputFilter::parseOp(const TQString ¶meter) { return changeMode(parameter,'o','+'); } OutputFilterResult OutputFilter::parseDeop(const TQString &ownNick, const TQString ¶meter) { return changeMode(addNickToEmptyNickList(ownNick,parameter),'o','-'); } OutputFilterResult OutputFilter::parseHop(const TQString ¶meter) { return changeMode(parameter, 'h', '+'); } OutputFilterResult OutputFilter::parseDehop(const TQString &ownNick, const TQString ¶meter) { return changeMode(addNickToEmptyNickList(ownNick,parameter), 'h', '-'); } OutputFilterResult OutputFilter::parseVoice(const TQString ¶meter) { return changeMode(parameter,'v','+'); } OutputFilterResult OutputFilter::parseUnvoice(const TQString &ownNick, const TQString ¶meter) { return changeMode(addNickToEmptyNickList(ownNick,parameter),'v','-'); } OutputFilterResult OutputFilter::parseJoin(TQString& channelName) { OutputFilterResult result; if(channelName.contains(",")) // Protect against #foo,0 tricks channelName = channelName.remove(",0"); //else if(channelName == "0") // FIXME IRC RFC 2812 section 3.2.1 if (channelName.isEmpty()) { if (destination.isEmpty() || !isAChannel(destination)) return usage(i18n("Usage: %1JOIN [password]").arg(commandChar)); channelName=destination; } else if (!isAChannel(channelName)) channelName = "#" + channelName.stripWhiteSpace(); Channel* channel = m_server->getChannelByName(channelName); if (channel) { // Note that this relies on the channels-flush-nicklists-on-disconnect behavior. if (!channel->numberOfNicks()) result.toServer = "JOIN " + channelName; if (channel->joined()) emit showView (channel); } else result.toServer = "JOIN " + channelName; return result; } OutputFilterResult OutputFilter::parseKick(const TQString ¶meter) { OutputFilterResult result; if(isAChannel(destination)) { // get nick to kick TQString victim = parameter.left(parameter.find(" ")); if(victim.isEmpty()) { result = usage(i18n("Usage: %1KICK [reason]").arg(commandChar)); } else { // get kick reason (if any) TQString reason = parameter.mid(victim.length() + 1); // if no reason given, take default reason if(reason.isEmpty()) { reason = m_server->getIdentity()->getKickReason(); } result.toServer = "KICK " + destination + ' ' + victim + " :" + reason; } } else { result = error(i18n("%1KICK only works from within channels.").arg(commandChar)); } return result; } OutputFilterResult OutputFilter::parsePart(const TQString ¶meter) { OutputFilterResult result; // No parameter, try default part message if(parameter.isEmpty()) { // But only if we actually are in a channel if(isAChannel(destination)) { result.toServer = "PART " + destination + " :" + m_server->getIdentity()->getPartReason(); } else { result = error(i18n("%1PART without parameters only works from within a channel or a query.").arg(commandChar)); } } else { // part a given channel if(isAChannel(parameter)) { // get channel name TQString channel = parameter.left(parameter.find(" ")); // get part reason (if any) TQString reason = parameter.mid(channel.length() + 1); // if no reason given, take default reason if(reason.isEmpty()) { reason = m_server->getIdentity()->getPartReason(); } result.toServer = "PART " + channel + " :" + reason; } // part this channel with a given reason else { if(isAChannel(destination)) { result.toServer = "PART " + destination + " :" + parameter; } else { result = error(i18n("%1PART without channel name only works from within a channel.").arg(commandChar)); } } } return result; } OutputFilterResult OutputFilter::parseTopic(const TQString ¶meter) { OutputFilterResult result; // No parameter, try to get current topic if(parameter.isEmpty()) { // But only if we actually are in a channel if(isAChannel(destination)) { result.toServer = "TOPIC " + destination; } else { result = error(i18n("%1TOPIC without parameters only works from within a channel.").arg(commandChar)); } } else { // retrieve or set topic of a given channel if(isAChannel(parameter)) { // get channel name TQString channel=parameter.left(parameter.find(" ")); // get topic (if any) TQString topic=parameter.mid(channel.length()+1); // if no topic given, retrieve topic if(topic.isEmpty()) { m_server->requestTopic(channel); } // otherwise set topic there else { result.toServer = "TOPIC " + channel + " :"; //If we get passed a ^A as a topic its a sign we should clear the topic. //Used to be a \n, but those get smashed by TQStringList::split and readded later //Now is not the time to fight with that. FIXME //If anyone out there *can* actually set the topic to a single ^A, now they have to //specify it twice to get one. if (topic =="\x01\x01") result.toServer += '\x01'; else if (topic!="\x01") result.toServer += topic; } } // set this channel's topic else { if(isAChannel(destination)) { result.toServer = "TOPIC " + destination + " :" + parameter; } else { result = error(i18n("%1TOPIC without channel name only works from within a channel.").arg(commandChar)); } } } return result; } void OutputFilter::parseAway(TQString& reason) { if (reason.isEmpty() && m_server->isAway()) m_server->requestUnaway(); else m_server->requestAway(reason); } void OutputFilter::parseBack() { m_server->requestUnaway(); } OutputFilterResult OutputFilter::parseNames(const TQString ¶meter) { OutputFilterResult result; result.toServer = "NAMES "; if (parameter.isNull()) { return error(i18n("%1NAMES with no target may disconnect you from the server. Specify '*' if you really want this.").arg(commandChar)); } else if (parameter != TQChar('*')) { result.toServer.append(parameter); } return result; } OutputFilterResult OutputFilter::parseClose(TQString parm) { if (parm.isEmpty()) parm=destination; if (isAChannel(parm) && m_server->getChannelByName(parm)) m_server->getChannelByName(parm)->closeYourself(false); else if (m_server->getQueryByName(parm)) m_server->getQueryByName(parm)->closeYourself(false); else if (parm.isEmpty()) // this can only mean one thing.. we're in the Server tab m_server->closeYourself(false); else return usage(i18n("Usage: %1close [window] closes the named channel or query tab, or the current tab if none specified.").arg(commandChar)); return OutputFilterResult(); } OutputFilterResult OutputFilter::parseQuit(const TQString &reason) { OutputFilterResult result; result.toServer = "QUIT :"; // if no reason given, take default reason if(reason.isEmpty()) result.toServer += m_server->getIdentity()->getQuitReason(); else result.toServer += reason; return result; } OutputFilterResult OutputFilter::parseNotice(const TQString ¶meter) { OutputFilterResult result; TQString recipient = parameter.left(parameter.find(" ")); TQString message = parameter.mid(recipient.length()+1); if(parameter.isEmpty() || message.isEmpty()) { result = usage(i18n("Usage: %1NOTICE ").arg(commandChar)); } else { result.typeString = i18n("Notice"); result.toServer = "NOTICE " + recipient + " :" + message; result.output=i18n("%1 is the message, %2 the recipient nickname","Sending notice \"%2\" to %1.").arg(recipient).arg(message); result.type = Program; } return result; } OutputFilterResult OutputFilter::parseMe(const TQString ¶meter, const TQString &destination) { OutputFilterResult result; if (!destination.isEmpty() && !parameter.isEmpty()) { result.toServer = "PRIVMSG " + destination + " :" + '\x01' + "ACTION " + parameter + '\x01'; result.output = parameter; result.type = Action; } else { result = usage(i18n("Usage: %1ME text").arg(commandChar)); } return result; } OutputFilterResult OutputFilter::parseMsg(const TQString &myNick, const TQString ¶meter, bool isQuery) { OutputFilterResult result; TQString recipient = parameter.section(" ", 0, 0, TQString::SectionSkipEmpty); TQString message = parameter.section(" ", 1); TQString output; if (recipient.isEmpty()) { result = error("Error: You need to specify a recipient."); return result; } if (isQuery && m_server->isAChannel(recipient)) { result = error("Error: You cannot open queries to channels."); return result; } if (message.stripWhiteSpace().isEmpty()) { //empty result - we don't want to send any message to the server if (!isQuery) { result = error("Error: You need to specify a message."); return result; } } else if (message.startsWith(commandChar+"me")) { result.toServer = "PRIVMSG " + recipient + " :" + '\x01' + "ACTION " + message.mid(4) + '\x01'; output = TQString("* %1 %2").arg(myNick).arg(message.mid(4)); } else { result.toServer = "PRIVMSG " + recipient + " :" + message; output = message; } ::Query *query; if (isQuery || output.isEmpty()) { //if this is a /query, always open a query window. //treat "/msg nick" as "/query nick" //Note we have to be a bit careful here. //We only want to create ('obtain') a new nickinfo if we have done /query //or "/msg nick". Not "/msg nick message". NickInfoPtr nickInfo = m_server->obtainNickInfo(recipient); query = m_server->addQuery(nickInfo, true /*we initiated*/); //force focus if the user did not specify any message if (output.isEmpty()) emit showView(query); } else { //We have "/msg nick message" query = m_server->getQueryByName(recipient); } if (query && !output.isEmpty()) { if (message.startsWith(commandChar+"me")) //log if and only if the query open query->appendAction(m_server->getNickname(), message.mid(4)); else //log if and only if the query open query->appendQuery(m_server->getNickname(), output); } if (output.isEmpty()) return result; //result should be completely empty; //FIXME - don't do below line if query is focused result.output = output; result.typeString= recipient; result.type = PrivateMessage; return result; } OutputFilterResult OutputFilter::parseSMsg(const TQString ¶meter) { OutputFilterResult result; TQString recipient = parameter.left(parameter.find(" ")); TQString message = parameter.mid(recipient.length() + 1); if(message.startsWith(commandChar + "me")) { result.toServer = "PRIVMSG " + recipient + " :" + '\x01' + "ACTION " + message.mid(4) + '\x01'; } else { result.toServer = "PRIVMSG " + recipient + " :" + message; } return result; } OutputFilterResult OutputFilter::parseCtcp(const TQString ¶meter) { OutputFilterResult result; // who is the recipient? TQString recipient = parameter.section(' ', 0, 0); // what is the first word of the ctcp? TQString request = parameter.section(' ', 1, 1, TQString::SectionSkipEmpty).upper(); // what is the complete ctcp command? TQString message = parameter.section(' ', 2, 0xffffff, TQString::SectionSkipEmpty); TQString out = request; if (!message.isEmpty()) out+= ' ' + message; if (request == "PING") { unsigned int time_t = TQDateTime::currentDateTime().toTime_t(); result.toServer = TQString("PRIVMSG %1 :\x01PING %2\x01").arg(recipient).arg(time_t); result.output = i18n("Sending CTCP-%1 request to %2.").arg("PING").arg(recipient); } else { result.toServer = "PRIVMSG " + recipient + " :" + '\x01' + out + '\x01'; result.output = i18n("Sending CTCP-%1 request to %2.").arg(out).arg(recipient); } result.typeString = i18n("CTCP"); result.type = Program; return result; } OutputFilterResult OutputFilter::changeMode(const TQString ¶meter,char mode,char giveTake) { OutputFilterResult result; // TODO: Make sure this works with +l and +k also! TQString token; TQString tmpToken; TQStringList nickList = TQStringList::split(' ', parameter); if(nickList.count()) { // Check if the user specified a channel if(isAChannel(nickList[0])) { token = "MODE " + nickList[0]; // remove the first element nickList.remove(nickList.begin()); } // Add default destination if it is a channel else if(isAChannel(destination)) { token = "MODE " + destination; } // Only continue if there was no error if(token.length()) { unsigned int modeCount = nickList.count(); TQString modes; modes.fill(mode, modeCount); token += TQString(" ") + TQChar(giveTake) + modes; tmpToken = token; for(unsigned int index = 0; index < modeCount; index++) { if((index % 3) == 0) { result.toServerList.append(token); token = tmpToken; } token += ' ' + nickList[index]; } if(token != tmpToken) { result.toServerList.append(token); } } } return result; } OutputFilterResult OutputFilter::parseDcc(const TQString ¶meter) { OutputFilterResult result; // No parameter, just open DCC panel if(parameter.isEmpty()) { emit addDccPanel(); } else { TQString tmpParameter = parameter; TQStringList parameterList = TQStringList::split(' ', tmpParameter.replace("\\ ", "%20")); TQString dccType = parameterList[0].lower(); if(dccType=="close") { emit closeDccPanel(); } else if(dccType=="send") { if(parameterList.count()==1) // DCC SEND { emit requestDccSend(); } // DCC SEND else if(parameterList.count()==2) { emit requestDccSend(parameterList[1]); } // DCC SEND [file] ... else if(parameterList.count()>2) { // TODO: make sure this will work: //output=i18n("Usage: %1DCC SEND nickname [fi6lename] [filename] ...").arg(commandChar); KURL fileURL(parameterList[2]); //We could easily check if the remote file exists, but then we might //end up asking for creditionals twice, so settle for only checking locally if(!fileURL.isLocalFile() || TQFile::exists( fileURL.path() )) { emit openDccSend(parameterList[1],fileURL); } else { result = error(i18n("File \"%1\" does not exist.").arg(parameterList[2])); } } else // Don't know how this should happen, but ... { result = usage(i18n("Usage: %1DCC [SEND nickname filename]").arg(commandChar)); } } // TODO: DCC Chat etc. comes here else if(dccType=="chat") { if(parameterList.count()==2) { emit openDccChat(parameterList[1]); } else { result = usage(i18n("Usage: %1DCC [CHAT nickname]").arg(commandChar)); } } else { result = error(i18n("Unrecognized command %1DCC %2. Possible commands are SEND, CHAT, CLOSE.").arg(commandChar).arg(parameterList[0])); } } return result; } OutputFilterResult OutputFilter::sendRequest(const TQString &recipient,const TQString &fileName,const TQString &address,const TQString &port,unsigned long size) { OutputFilterResult result; TQString niftyFileName(fileName); /*TQFile file(fileName); TQFileInfo info(file);*/ result.toServer = "PRIVMSG " + recipient + " :" + '\x01' + "DCC SEND " + fileName + ' ' + address + ' ' + port + ' ' + TQString::number(size) + '\x01'; // Dirty hack to avoid printing ""name with spaces.ext"" instead of "name with spaces.ext" if ((fileName.startsWith("\"")) && (fileName.endsWith("\""))) niftyFileName = fileName.mid(1, fileName.length()-2); return result; } OutputFilterResult OutputFilter::passiveSendRequest(const TQString& recipient,const TQString &fileName,const TQString &address,unsigned long size,const TQString &token) { OutputFilterResult result; TQString niftyFileName(fileName); result.toServer = "PRIVMSG " + recipient + " :" + '\x01' + "DCC SEND " + fileName + ' ' + address + " 0 " + TQString::number(size) + ' ' + token + '\x01'; // Dirty hack to avoid printing ""name with spaces.ext"" instead of "name with spaces.ext" if ((fileName.startsWith("\"")) && (fileName.endsWith("\""))) niftyFileName = fileName.mid(1, fileName.length()-2); return result; } // Accepting Resume Request OutputFilterResult OutputFilter::acceptResumeRequest(const TQString &recipient,const TQString &fileName,const TQString &port,int startAt) { TQString niftyFileName(fileName); OutputFilterResult result; result.toServer = "PRIVMSG " + recipient + " :" + '\x01' + "DCC ACCEPT " + fileName + ' ' + port + ' ' + TQString::number(startAt) + '\x01'; // Dirty hack to avoid printing ""name with spaces.ext"" instead of "name with spaces.ext" if ((fileName.startsWith("\"")) && (fileName.endsWith("\""))) niftyFileName = fileName.mid(1, fileName.length()-2); return result; } OutputFilterResult OutputFilter::resumeRequest(const TQString &sender,const TQString &fileName,const TQString &port,TDEIO::filesize_t startAt) { TQString niftyFileName(fileName); OutputFilterResult result; /*TQString newFileName(fileName); newFileName.replace(" ", "_");*/ result.toServer = "PRIVMSG " + sender + " :" + '\x01' + "DCC RESUME " + fileName + ' ' + port + ' ' + TQString::number(startAt) + '\x01'; // Dirty hack to avoid printing ""name with spaces.ext"" instead of "name with spaces.ext" if ((fileName.startsWith("\"")) && (fileName.endsWith("\""))) niftyFileName = fileName.mid(1, fileName.length()-2); return result; } OutputFilterResult OutputFilter::acceptPassiveSendRequest(const TQString& recipient,const TQString &fileName,const TQString &address,const TQString &port,unsigned long size,const TQString &token) { OutputFilterResult result; TQString niftyFileName(fileName); // "DCC SEND" to receive a file sounds weird, but it's ok. result.toServer = "PRIVMSG " + recipient + " :" + '\x01' + "DCC SEND " + fileName + ' ' + address + ' ' + port + ' ' + TQString::number(size) + ' ' + token + '\x01'; // Dirty hack to avoid printing ""name with spaces.ext"" instead of "name with spaces.ext" if ((fileName.startsWith("\"")) && (fileName.endsWith("\""))) niftyFileName = fileName.mid(1, fileName.length()-2); return result; } OutputFilterResult OutputFilter::parseInvite(const TQString ¶meter) { OutputFilterResult result; if(parameter.isEmpty()) { result = usage(i18n("Usage: %1INVITE [channel]").arg(commandChar)); } else { TQString nick = parameter.section(' ', 0, 0, TQString::SectionSkipEmpty); TQString channel = parameter.section(' ', 1, 1, TQString::SectionSkipEmpty); if(channel.isEmpty()) { if(isAChannel(destination)) { channel = destination; } else { result = error(i18n("%1INVITE without channel name works only from within channels.").arg(commandChar)); } } if(!channel.isEmpty()) { if(isAChannel(channel)) { result.toServer = "INVITE " + nick + ' ' + channel; } else { result = error(i18n("%1 is not a channel.").arg(channel)); } } } return result; } OutputFilterResult OutputFilter::parseExec(const TQString& parameter) { OutputFilterResult result; if(parameter.isEmpty()) { result = usage(i18n("Usage: %1EXEC