You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdenetwork/ksirc/chanparser.cpp

1048 lines
31 KiB

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "alistbox.h"
#include "chanparser.h"
#include "ksopts.h"
#include "control_message.h"
#include "ssfeprompt.h"
#include "toplevel.h"
#include "ksircprocess.h"
#include "ksview.h"
#include <stdio.h>
#include <tqregexp.h>
#include <tqapplication.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kdebug.h>
#include <tqptrlist.h>
// Static parser table is "initialized"
TQDict<parseFunc> ChannelParser::parserTable;
ChannelParser::ChannelParser(KSircTopLevel *_top)
{
top = _top;
/*
* Initial helper variables
*/
prompt_active = false;
current_item = -1;
top_item = 0;
if(parserTable.isEmpty() == TRUE){
parserTable.setAutoDelete(TRUE);
parserTable.insert("`l`", new parseFunc(&ChannelParser::parseSSFEClear));
parserTable.insert("`s`", new parseFunc(&ChannelParser::parseSSFEtqStatus));
parserTable.insert("`i`", new parseFunc(&ChannelParser::parseSSFEInit));
parserTable.insert("`t`", new parseFunc(&ChannelParser::parseSSFEMsg));
parserTable.insert("`o`", new parseFunc(&ChannelParser::parseSSFEOut));
parserTable.insert("`p`", new parseFunc(&ChannelParser::parseSSFEPrompt));
parserTable.insert("`P`", new parseFunc(&ChannelParser::parseSSFEPrompt));
parserTable.insert("`R`", new parseFunc(&ChannelParser::parseSSFEReconnect));
// The rest are *** info message
parserTable.insert("***", new parseFunc(&ChannelParser::parseINFOInfo));
parserTable.insert("*E*", new parseFunc(&ChannelParser::parseINFOError));
parserTable.insert("*!*", new parseFunc(&ChannelParser::parseINFONicks)); // Normal
parserTable.insert("*C*", new parseFunc(&ChannelParser::parseINFONicks)); // 1st line
parserTable.insert("*c*", new parseFunc(&ChannelParser::parseINFONicks)); // Last line
parserTable.insert("*#*", new parseFunc(&ChannelParser::parseINFONicks)); // Non enhanced
parserTable.insert("*$*", new parseFunc(&ChannelParser::parseINFONicks)); // Enhanced turned off
parserTable.insert("*>*", new parseFunc(&ChannelParser::parseINFOJoin));
parserTable.insert("*<*", new parseFunc(&ChannelParser::parseINFOPart));
parserTable.insert("*N*", new parseFunc(&ChannelParser::parseINFOChangeNick));
parserTable.insert("*+*", new parseFunc(&ChannelParser::parseINFOMode));
parserTable.insert("*T*", new parseFunc(&ChannelParser::parseINFOTopic));
// End of info message
parserTable.insert("* ", new parseFunc(&ChannelParser::parseCTCPAction));
}
}
parseResult *ChannelParser::parse(TQString string)
{
// for older TQts
parseFunc *pf;
if(string.length() < 3){
return new parseError(string, TQString("Dumb string, too short"));
}
/**
* Start pre-parsing the strings to make them fit the 3 character
* parser codes, etc
*/
/*
* SSFE control messages are too long, so we convert the
* messges into a 3 character code, `#ssfe#\S becomes `\S`
*/
if ((string[0] == '`') & (string.length() > 7))
{
TQString prefix = "`"+string[7]+"`";
string = prefix + TQString(" ") + string.mid(8).stripWhiteSpace();
}
else if((string[0] == '*') && (string[1] == ' ')) {
string.insert(1, ' ');
}
// Pre-parsing is now complete
pf = parserTable[string.mid(0, 3)];
if(pf != 0x0){
parseResult *result = (this->*(pf->parser))(string);
if (result)
return result;
}
else
{
// debug("No handler for: %s", string.data());
}
// Little bit of past parsing to catch one we've missed
if((string[0] == '*') && (string[2] == '*')) {
string.remove(0, 3);
return new parseSucc(string, ksopts->infoColor, "user|servinfo");
}
// If it's unkown we just fall out of the function
return 0;
}
parseResult * ChannelParser::parseSSFEClear(TQString string)
{
// top->mainw->clear();
top->clearWindow();
// top->mainw->tqrepaint(TRUE);
string.truncate(0);
return new parseSucc(TQString()); // Null string, don't display anything
}
parseResult * ChannelParser::parseSSFEtqStatus(TQString string)
{
string.remove(0, 12); // strip off the first 12 characters "<junk> [sirc] "
if(string.length() == 0)
return new parseError("", i18n("Unable to parse status string"));
//kdDebug(5008) << "String: " << string << endl;
TQRegExp rx("(\\S+).*\\(*([+-]*[+-\\w\\d]*)\\)*.*on (\\S+) \\((\\S+)\\)");
if(rx.search(string) == -1){
return new parseError("", i18n("Unable to parse status (no known format) string"));
}
TQString nick = rx.cap(1);
TQString modes = rx.cap(2);
TQString chan = rx.cap(3);
TQString chanmode = rx.cap(4);
/*
* fix up modes which may have gotten the (away) part
*/
if(modes.contains("away")){
modes = "";
}
bool away = false;
if(string.contains("(away)"))
away = true;
if(away){
chan.prepend(i18n("Away-"));
}
nickListItem *nickItem = top->nicks->item( top->nicks->findNick( nick ) );
if ( nickItem ) {
if(nickItem->away() != away){
nickItem->setAway( away );
top->nicks->viewport()->tqrepaint( top->nicks->tqitemRect( nickItem ), false );
}
nickItem->forceColour(&ksopts->ownNickColor);
}
top->ksircProcess()->setNick(nick);
if (chanmode.findRev("t") != -1)
top->channelButtons->setProtectMode(true);
else top->channelButtons->setProtectMode(false);
if (chanmode.findRev("m") != -1)
top->channelButtons->setModerateMode(true);
else top->channelButtons->setModerateMode(false);
if (chanmode.findRev("n") != -1)
top->channelButtons->setNooutsideMode(true);
else top->channelButtons->setNooutsideMode(false);
if (chanmode.findRev("i") != -1)
top->channelButtons->setMenuItemMode(0, true);
else top->channelButtons->setMenuItemMode(0, false);
if (chanmode.findRev("s") != -1)
top->channelButtons->setMenuItemMode(3, true);
else top->channelButtons->setMenuItemMode(3, false);
if (modes.findRev("i") != -1)
top->channelButtons->setMenuItemMode(4, true);
else top->channelButtons->setMenuItemMode(4, false);
if (modes.findRev("w") != -1)
top->channelButtons->setMenuItemMode(5, true);
else top->channelButtons->setMenuItemMode(5, false);
if (modes.findRev("s") != -1)
top->channelButtons->setMenuItemMode(6, true);
else top->channelButtons->setMenuItemMode(6, false);
TQString status_line = TQString("%1 (%2) %3 (%4) ").tqarg(chan).tqarg(chanmode).tqarg(nick).tqarg(modes);
/*
* Go srearching for key and limit messages
*/
TQRegExp rxKey("<key: (\\S+)>");
if(rxKey.search(string) >= 0){
top->channelButtons->setMenuItemMode(2, true);
status_line += TQString("<key: %1>").tqarg(rxKey.cap(1));
}
else {
top->channelButtons->setMenuItemMode(2, false);
}
TQRegExp rxLimit("<limit: (\\S+)>");
if(rxLimit.search(string) >= 0){
top->channelButtons->setMenuItemMode(1, true);
status_line += TQString("<limit: %1>").tqarg(rxLimit.cap(1));
}
else {
top->channelButtons->setMenuItemMode(1, false);
}
if(ksopts->displayTopic){
if(top->topic().length() > 0)
status_line += "T: " + top->topic();
else
status_line += "T: " + i18n("<No Topic Set>");
}
if(top->caption != status_line){
if(nick[0] == '@' || (nick[0] == '*' && nick[1] == '@')) {
// If we're an op,,
// update the nicks popup menu
top->channelButtons->setButtonsEnabled(true); // set the buttons enabled if were an op
top->opami = TRUE;
} // opami = true sets us to an op
else {
top->channelButtons->setButtonsEnabled(false); // set the buttons enabled if were an op
top->opami = FALSE;
} // FALSE, were not an ops
top->UserUpdateMenu(); // update the menu
top->setCaption(status_line);
top->setIconText(status_line);
if(top->ticker) {
top->ticker->setCaption(status_line);
}
top->caption = status_line; // Make copy so we're not
// constantly changing the title bar
}
return new parseSucc(TQString()); // Null string, don't display anything
}
parseResult * ChannelParser::parseSSFEInit(TQString)
{
return new parseSucc(TQString()); // Null string, don't display anything
}
parseResult * ChannelParser::parseSSFEOut(TQString)
{
return new parseSucc(TQString()); // Null string, don't display anything
}
parseResult * ChannelParser::parseSSFEMsg(TQString string)
{
if(string.length() > 100)
return new parseError(TQString(), i18n("String length for nick is greater than 100 characters. This is unacceptably long."));
int l = string.length();
if (l <= 0)
return new parseError(string, i18n("String not long enough"));
return new parseSucc(TQString()); // Null string, don't display anything
}
parseResult * ChannelParser::parseSSFEPrompt(TQString string)
{
if(prompt_active == FALSE){
TQString prompt, caption;
ssfePrompt *sp;
// Flush the screen.
// First remove the prompt message from the Buffer.
// (it's garunteed to be the first one)
top->LineBuffer.remove( *top->LineBuffer.begin() );
top->Buffer = FALSE;
top->sirc_receive(TQString(""));
// "'[pP]' " gives 4 spaces
if(string.length() < 5)
caption = i18n("");
else
caption = string.mid(3);
prompt_active = TRUE;
// If we use this, then it blows up
// if we haven't popped up on the remote display yet.
KSirc::TextParagIterator it = top->mainw->firstParag();
TQString last;
while(it.atEnd() == FALSE) {
last = it.plainText();
++it;
}
if(last[0] == '['){ /* strip time stamp */
prompt = last.mid(last.find(' '));
}
else {
prompt = last;
}
sp = new ssfePrompt(prompt, 0);
sp->setCaption(caption);
if(string[1] == 'P')
sp->setPassword(TRUE);
sp->exec();
// cerr << "Entered: " << sp->text() << endl;
prompt = sp->text();
prompt += "\n";
emit top->outputUnicodeLine(prompt);
delete sp;
prompt_active = FALSE;
}
return new parseSucc(TQString()); // Null string, don't display anything
}
parseResult * ChannelParser::parseSSFEReconnect(TQString)
{
if(top->channelInfo().channel()[0] == '#' ||
top->channelInfo().channel()[0] == '&'){
TQString str = "/join " + TQString(top->channelInfo().channel()) + "\n";
emit top->outputUnicodeLine(str);
}
return new parseSucc(TQString()); // Null string, don't display anything
}
parseResult * ChannelParser::parseINFOInfo(TQString string)
{
string.remove(0, 3); // takes off the junk
return new parseSucc(string, ksopts->infoColor, "user|servinfo"); // Null string, don't display anything
}
parseResult * ChannelParser::parseINFOError(TQString string)
{
string.remove(0, 3); // strip the junk
return new parseSucc(string,ksopts->errorColor, "user|error"); // Null string, don't display anything
}
parseResult * ChannelParser::parseINFONicks(TQString in_string)
{
TQString string = in_string;
TQString channel_name;
bool clear_box = FALSE;
// Check to see if it's a continued line
if(string[1] == 'C'){
string[1] = '!';
clear_box = TRUE;
}
if(string[1] == '#'){
string[1] = '!';
clear_box = FALSE;
}
else if(string[1] == 'c'){
if(current_item > 0)
top->nicks->setCurrentItem(current_item);
top->nicks->setTopItem(top_item);
top->nicks->tqrepaint(TRUE);
return new parseSucc(TQString()); // Parsing ok, don't print anything though
}
else if(string[1] == '$'){
top->nicks->clearAdvOps();
//kdDebug(5008) << "Turning off advanced ops" << endl;
return new parseSucc(TQString()); // Parsing ok, don't print anything though
}
// Get the channel name portion of the string
// Search for the first space, since : can be embeded into channel names.
//count = sscanf(string, "*!* Users on %100[^ ]", channelInfo().channel());
// *!* Users on #TEST: boren asj asj_
TQRegExp rx("\\*\\S\\* Users on (\\S+): (.+)");
if(rx.search(string) == -1){
return new parseError(string, i18n("Could not find channel name"));
}
channel_name = rx.cap(1);
if (channel_name.lower() != top->channelInfo().channel().lower()){
string.remove(0,3);
return new parseSucc(string,ksopts->infoColor,"user|misc4");
}
if(clear_box == TRUE){
current_item = top->nicks->currentItem();
top_item = top->nicks->topItem();
top->nicks->clear();
}
//int start = string.find(": ", 0, FALSE); // Find start of nicks
//if (start < 0)
// return new parseError(string, i18n("Could not find start of nicks"));
//
//place_holder = new char[string.length()];
//strcpy(place_holder, string.ascii()+start+2);
//nick = strtok(place_holder, " ");
// while(nick != 0x0){ // While there's nick to go...
TQStringList nicks = TQStringList::split(TQRegExp("\\s+"), rx.cap(2));
for ( TQStringList::Iterator it = nicks.begin(); it != nicks.end(); ++it ) {
TQString nick = *it;
nickListItem *irc = new nickListItem();
bool done = FALSE;
uint i;
for(i = 0; i < nick.length();i++){
switch(nick[0].tqunicode()){
case '@':
irc->setOp(TRUE);
nick.remove(0,1);
break;
case '+':
irc->setVoice(TRUE);
nick.remove(0,1);
break;
case '#':
irc->setAway(TRUE);
nick.remove(0,1);
break;
case '*':
irc->setIrcOp(TRUE);
nick.remove(0,1);
break;
default:
done = TRUE;
}
if(done == TRUE)
break;
}
if(nick == top->ksircProcess()->getNick()){
irc->forceColour(&ksopts->ownNickColor);
}
irc->setText(nick);
top->nicks->inSort(irc);
}
return new parseSucc(TQString()); // Parsing ok, don't print anything though
}
parseResult * ChannelParser::parseINFOJoin(TQString string)
{
string.remove(0, 4); // strip *>* to save a few compares
// You have joined channel #Linux
TQRegExp rx("You have joined channel (\\S+)");
if(rx.search(string) != -1){
//TQString channel = rx.cap(1).lower();
TQString channel = rx.cap(1);
//kdDebug(5008) << "Channel: " << channel << endl;
if(top->channelInfo().channel() != channel) {
KSircChannel ci(top->channelInfo().server(), channel);
kdDebug(5008) << "Warning: we got a channel join yet me don't belong to it!!! Assuming no key!" << endl;
kdDebug(5008) << "String was: " << string << endl;
kdDebug(5008) << "We think the channel is: " << channel << " we are: " << top->channelInfo().channel()<< endl;
emit top->open_toplevel(ci);
}
return new parseJoinPart(" " + string, ksopts->channelColor, "user|join");
}
// reef-diddy (nenernener@xnet-3B34A9E2.snet.net) has joined channel #aquaria
rx.setPattern("(\\S+) .+ has joined channel (\\S+)");
if(rx.search(string) != -1){
TQString nick = rx.cap(1);
TQString channel = rx.cap(2).lower();
//kdDebug(5008) << "Channel: " << channel << " nick: " << nick << endl;
if(top->channelInfo().channel().lower() != channel){
return new parseWrongChannel(" " + string, ksopts->errorColor, "user|join");
}
// nicks->insertItem(s3, 0); // add the sucker
top->nicks->inSort(nick);
top->addCompleteNick(nick);
highlightNick(string, nick);
return new parseJoinPart(" " + string, ksopts->channelColor, "user|join");
}
return 0; // ??
}
parseResult * ChannelParser::parseINFOPart(TQString string)
{
bool foundNick = false;
TQString pixname = "user|kick";
TQString nick("");
string.remove(0, 4); // clear junk
// Multiple type of parts, a signoff or a /part
// Each get's get nick in a diffrent localtion
// Set we search and find the nick and the remove it from the nick list
// 1. /quit, signoff, nick after "^Singoff: "
// 2. /part, leave the channek, nick after "has left \w+$"
// 3. /kick, kicked off the channel, nick after "kicked off \w+$"
//
// Signoff: looser
TQRegExp rx("Signoff: (\\S+)");
if(rx.search(string) != -1) {
nick = rx.cap(1);
foundNick = true;
pixname = "user|X";
highlightNick(string, nick);
}
/*
* Check for "You" before everyone else or else the next
* case will match it
* You have left channel <channel>
*/
rx.setPattern("You have left channel (\\S+)");
if((foundNick == false) && (rx.search(string) != -1)) {
TQString channel = rx.cap(1);
if(top->channelInfo().channel().lower() == channel.lower()) {
TQApplication::postEvent(top, new TQCloseEvent());
// WE'RE DEAD
return new parseSucc(TQString());
}
pixname = "user|part";
}
/*
* Same as above, check your own state first
* You have been kicked off channel <channel>
*/
rx.setPattern("You have been kicked off channel (\\S+)");
if((foundNick == false) && (rx.search(string) != -1)) {
TQString channel = rx.cap(1);
if(top->channelInfo().channel().lower() != channel.lower())
return new parseWrongChannel(string, ksopts->errorColor, "user|kick");
if (ksopts->autoRejoin == TRUE)
{
TQString str = TQString("/join %1\n").tqarg(top->channelInfo().channel());
emit top->outputUnicodeLine(str);
/* if(top->ticker)
top->ticker->show();
else*/
top->show();
}
else
{
if(top->KickWinOpen != false)
return new parseError(" " + string, i18n("Kick window open"));
top->KickWinOpen = true;
int result = KMessageBox::questionYesNo(top, string, i18n("You Have Been Kicked"), i18n("Rejoin"), i18n("Leave"));
if (result == KMessageBox::Yes)
{
TQString str = TQString("/join %1\n").tqarg(top->channelInfo().channel());
emit top->outputUnicodeLine(str);
/* if(top->ticker)
* top->ticker->show();
* else*/
top->show();
return new parseJoinPart(" " + string, ksopts->channelColor, "user|kick");
}
else
{
// WE'RE DEAD
TQApplication::postEvent(top, new TQCloseEvent());
top->KickWinOpen = false;
}
}
pixname = "user|kick";
}
/*
* <nick> has left channel <channel>
*/
rx.setPattern("(\\S+) has left channel (\\S+)");
if((foundNick == false) && (rx.search(string) != -1)) {
nick = rx.cap(1);
TQString channel = rx.cap(2);
// kdDebug(5008) << "Nick: " << nick << " Channel: " << channel << " top: " << top->channelInfo().channel() << endl;
if(top->channelInfo().channel().lower() == channel.lower()) {
foundNick = true;
}
else{
return new parseWrongChannel(TQString());
}
pixname = "user|part";
highlightNick(string, nick);
}
/*
* "<nick> has been kicked off channel <channel>"
*/
rx.setPattern("(\\S+) has been kicked off channel (\\S+)");
if((foundNick == false) && (rx.search(string) != -1)) {
nick = rx.cap(1);
TQString channel = rx.cap(2);
if(top->channelInfo().channel().lower() == channel.lower()) {
foundNick = true;
} else {
return new parseWrongChannel(TQString());
}
highlightNick(string, nick);
pixname = "user|kick";
}
if (foundNick) {
top->removeCompleteNick(nick);
int index = top->nicks->findNick(nick);
if(index >= 0){
top->nicks->removeItem(index);
return new parseJoinPart(" " + string, ksopts->channelColor, pixname);
}
else {
return new parseJoinPart(TQString());
}
}
else {
return new parseError(" " + string, i18n("Failed to parse part/kick/leave/quit message"));
}
return 0;
}
parseResult * ChannelParser::parseINFOChangeNick(TQString string)
{
//char old_nick[101], new_nick[101];
TQString old_nick, new_nick;
string.remove(0, 4); // Remove the leading *N* and space
/*
* *N* asj_ is now known as bleh
*/
//kdDebug(5008) << "Nick change: " << string << endl;
TQRegExp rx("(\\S+) is now known as (\\S+)");
if(rx.search(string) == -1){
if(string.contains("already taken")){
return new parseSucc(" " + string, ksopts->errorColor, "user|error");
}
return new parseError(i18n("Unable to parse: %1").tqarg(string), i18n("Unable to parse change nick code"));
}
old_nick = rx.cap(1);
new_nick = rx.cap(2);
// If we have a window open talking to the nick
// Change the nick to the new one.
if((top->channelInfo().channel()[0] != '#' || top->channelInfo().channel()[0] != '&') &&
(top->channelInfo().channel() == old_nick)){
if(!top->ksircProcess()->mrList()[new_nick.lower()]){
top->control_message(CHANGE_CHANNEL, new_nick.lower());
}
}
highlightNick(string, old_nick);
highlightNick(string, new_nick);
// search the list for the nick and remove it
// since the list is source we should do a binary search...
int found = top->nicks->findNick(old_nick);
if(found >= 0){ // If the nick's in the nick list, change it and display the change
// save current selection
int selection = top->nicks->currentItem();
// Get the old item, and create a new one
nickListItem *it = top->nicks->item(found);
nickListItem *irc = new nickListItem(*it);
irc->setText(new_nick);
top->nicks->removeItem(found); // remove old nick
top->nicks->inSort(irc);
top->changeCompleteNick(old_nick, new_nick);
top->nicks->setCurrentItem(selection);
top->nicks->tqrepaint(TRUE);
// We're done, so let's finish up
return new parseSucc(" " + string, ksopts->channelColor, "user|join");
}
else {
if(top->channelInfo().channel() == new_nick ||
top->channelInfo().channel() == old_nick)
return new parseSucc(" " + string, ksopts->channelColor, "user|elipsis");
else
return new parseSucc(TQString());
}
// warning("Toplevel-N: nick change search failed on %s", s3.data());
// return new parseSucc(TQString());
}
class mode_info {
public:
mode_info(bool op, TQChar mode, TQString arg);
bool op() const;
TQChar mode() const;
TQString arg() const;
private:
const bool m_op;
const TQChar m_mode;
const TQString m_arg;
};
mode_info::mode_info(bool op, TQChar mode, TQString arg) :
m_op(op),
m_mode(mode),
m_arg(arg)
{
}
bool mode_info::op() const {
return m_op;
}
TQChar mode_info::mode() const {
return m_mode;
}
TQString mode_info::arg() const {
return m_arg;
}
parseResult * ChannelParser::parseINFOMode(TQString string)
{
// Basic idea here is simple, go through the mode change and
// assign each mode a + or a - and an argument or "" if there is
// none. After that each mode change it looked at to see if
// we should handle it in any special way.
// Strip off leading sirc info
string.remove(0, 4);
/*
* 1k is pretty safe since KProcess returns 1 k blocks, and lines don't get split between reads. This is emprical
*/
TQString modes, args, channel;
int found = 0;
if(string.find("for user") >= 0)
return new parseSucc(" " + string, ksopts->infoColor, "user|mode");
/*
* We need to 2 scanf's, one for the case of arguments, and one for no args.
*/
TQRegExp rx("Mode change \"(\\S+) *([^\"]*)\" on channel (\\S+)");
if(rx.search(string) >= 0){
modes = rx.cap(1);
args = rx.cap(2);
channel = rx.cap(3);
found = 1;
}
rx.setPattern("Mode for channel (\\S+) is \"([^\" ]+)\"");
if(found == 0 &&
rx.search(string) >= 0){
channel = rx.cap(1);
modes = rx.cap(2);
found = 1;
}
rx.setPattern("Your user mode is");
if(found == 0 &&
rx.search(string) >= 0){
/*
* Don't parse user mode requests
*/
return new parseSucc(" " + string, ksopts->infoColor, "user|mode");
}
if(found == 0)
return new parseError(" Failed to parse mode change: " + string, TQString());
/*
* op specifie if it's a + or -. tru is + false is -
*/
bool op = true;
/*
* arglist is the list of argument
* we use the itirator to tstep through the list
* as need be
*/
TQStringList arglist = TQStringList::split(" ", args);
TQStringList::Iterator ai = arglist.begin();
/*
* the ptr list structure contains the parsed contents
*/
TQPtrList<const mode_info> pmList;
pmList.setAutoDelete(true);
for(uint pos = 0; pos < modes.length(); pos++){
switch(modes.tqat(pos).tqunicode()){
case '+':
op = true;
break;
case '-':
op = false;
break;
case 'l': // Chan limits
/*
* -l doesn't take any arguments, so just add the mode and break
* +l otoh does, so read the argument
*/
if(op == false){
pmList.append(new mode_info(op, 'l', TQString()));
break;
}
case 'o': // Op, arg is the nick
case 'v': // Voice, arg is the nick
case 'b': // Ban, arg is mask banned
case 'k': // kcik, arg is nick
if(ai == NULL)
return new parseError(i18n("Unable to parse mode change: %1").tqarg(string), TQString());
pmList.append(new mode_info(op, modes.at(pos), *ai));
ai++;
break;
case 'i': // Invite only
case 'n': // No message to chan
case 'p': // Private
case 'm': // Moderated
case 's': // Secret
case 't': // Topic setable by ops
case 'R': // (Dalnet) only registered may join
case 'r': // (Dalnet) only registered may join or something
/*
* Mode changes which don't take args
*/
pmList.append(new mode_info(op, modes.at(pos), TQString()));
break;
default:
kdDebug(5008) << "Unknown mode change: " << modes.mid(pos, 1) << " Assume no args" << endl;
pmList.append(new mode_info(op, modes.at(pos), TQString()));
}
}
// We have the modes set in mode and arg, now we go though
// looking at each mode seeing if we should handle it.
bool mode_o_plus = false;
bool mode_o_minus = false;
bool mode_b_plus = false;
bool mode_b_minus = false;
TQPtrListIterator<const mode_info> it(pmList);
const mode_info *mi;
while ( (mi = it.current()) != 0 ) {
++it;
/*
* Look at the second character, it's uniq, check for +,- latter
*/
if(mi->mode().tqunicode() == 'o'){
mode_o_plus = mi->op();
mode_o_minus = !mi->op();
if(top->ksircProcess()->getNick() == mi->arg())
top->channelButtons->setButtonsEnabled(mi->op());
if(mi->arg().length() == 0){
qWarning("Invalid nick in +/- o mode change");
continue;
}
int offset = top->nicks->findNick(mi->arg());
if(offset >= 0){
nickListItem *irc = new nickListItem();
*irc = *top->nicks->item(offset);
top->nicks->removeItem(offset); // remove old nick
irc->setOp(mi->op());
// add new nick in sorted pass,with colour
top->nicks->inSort(irc);
top->nicks->tqrepaint(TRUE);
}
else{
kdDebug(5008) << "Toplevel+o: nick search failed on " << mi->arg() << endl;
}
}
else if(mi->mode() == 't'){
if(mi->op())
top->channelButtons->setProtectMode(true); // set on
else
top->channelButtons->setProtectMode(false); // set off
}
else if(mi->mode() == 'm'){
if(mi->op())
top->channelButtons->setModerateMode(true); // set on
else
top->channelButtons->setModerateMode(false); // set off
}
else if(mi->mode() == 'n'){
if(mi->op())
top->channelButtons->setNooutsideMode(true); // set on
else
top->channelButtons->setNooutsideMode(false); // set off
}
else if(mi->mode() == 'v'){
bool voice;
if(mi->op())
voice = TRUE;
else
voice = FALSE;
if(mi->arg().length() == 0){
qWarning("Invalid nick in +-v mode change");
continue;
}
int offset = top->nicks->findNick(mi->arg());
if(offset >= 0){
nickListItem *irc = new nickListItem();
*irc = *top->nicks->item(offset);
top->nicks->removeItem(offset); // remove old nick
irc->setVoice(voice) ;
// add new nick in sorted pass,with colour
top->nicks->inSort(irc);
top->nicks->tqrepaint();
}
}
else if(mi->mode() == 'b'){
if(mi->op())
mode_b_plus = true;
else
mode_b_minus = true;
}
else if(mi->mode() == 'k'){
if(mi->op()){
if(mi->arg().length() == 0){
qWarning("Invalid +k mode set, no argument!");
continue;
}
top->m_channelInfo.setKey(mi->arg());
}
else {
top->m_channelInfo.setKey(""); /* no key set anymore */
}
}
else{
TQChar c(mi->mode());
TQString m(&c, 1);
TQString o;
if(mi->op())
o = "+";
else
o = "-";
kdDebug(5008) << "Did not handle: " << o << m << " arg: " << mi->arg() << endl;
}
}
/*
* We're all done, so output the message and be done with it
*/
TQString pixname = "user|mode";
if(mode_o_plus)
pixname = "user|oplus";
else if(mode_o_minus)
pixname = "user|ominus";
else if(mode_b_plus)
pixname ="user|bplus";
else if(mode_b_minus)
pixname = "user|bminus";
return new parseSucc(" " + string, ksopts->infoColor, pixname);
}
parseResult * ChannelParser::parseCTCPAction(TQString string)
{
string.remove(0, 2); // * <something> use fancy * pixmap. Remove 2, leave one for space after te *
// why? looks cool for dorks
return new parseSucc(string, ksopts->textColor, "user|action");
}
parseResult * ChannelParser::parseINFOTopic(TQString string)
{
int found = 0;
string.remove(0, 4); // Remove the leading *T* and space
//kdDebug(5008) << "Topic parser: " << string << endl;
// Topic for #boo: this is a nice test
TQRegExp rx( "Topic for (\\S+): (.*)" );
if(rx.search( string ) != -1){
TQString channel = rx.cap(1);
TQString topic = rx.cap(2);
topic.replace( TQRegExp( "~~" ), "~" );
/*
* check where it's going.
* topic's maybe for other channels since they have no channel routing
* information, so route it to the right place if need be.
* If we're not on the channnel just fall through and display it
* on our channel, maybe the user asked for a topic of a different channel
*/
if(channel.lower() != top->channelInfo().channel().lower()){
if(top->ksircProcess()->mrList()[channel.lower()]){
KSircTopLevel *t = dynamic_cast<KSircTopLevel *>(top->ksircProcess()->mrList()[channel.lower()]);
if(t)
t->setTopic(topic);
}
}
else {
//kdDebug(5008) << "New topic: " << topic << endl;
top->setTopic( topic );
}
found = 1;
}
rx.setPattern("(\\S+) has changed the topic on channel (\\S+) to (.+)");
if(found == 0 && rx.search(string) != -1){
TQString nick = rx.cap(1);
TQString channel = rx.cap(2);
//kdDebug(5008) << "Channel: " << channel << endl;
if(top->channelInfo().channel().lower() == channel.lower()){
TQString topic = rx.cap(3);
//kdDebug(5008) << "Topic: " << topic << endl;
topic.replace(TQRegExp("~~"), "~");
/*
* topic is in double quotes, so remove them
*/
top->setTopic( topic.mid(1, topic.length()-2) );
TQString cmd = "/eval &dostatus();\n";
top->sirc_write(cmd);
}
highlightNick(string, nick);
}
return new parseSucc(" " + string, ksopts->infoColor, "user|topic");
}
void ChannelParser::highlightNick(TQString &string, TQString &nick)
{
TQRegExp rx(TQString("(^|\\s+)%1(\\s+|$)").tqarg(TQRegExp::escape(nick)));
string.replace(rx, "\\1~n" + nick + "~n\\2");
}