--Boundary-00=_j25CCxzeOwg/9jl Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline Hi guys ! I got a problem when closing a window ( a QMainWindow ) in an MDI widget. Here are the files that cause the problem. It's a segmentation fault And here is the output : Destructor called : closing channels and sending QUIT cmd to serv Destroying #gentoo item removed Leaving #gentoo unregistering channel channel unregistered Part cmd sent item destroyed Segmentation fault Thanks for help, Alex --Boundary-00=_j25CCxzeOwg/9jl Content-Type: text/x-c++src; charset="us-ascii"; name="beChannel.cpp" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="beChannel.cpp" // beIRC stuff #include "beChannel.h" #include "beConsole.h" #include "beLineView.h" // kvirc stuff #define HAVE_CONFIG_H #include "config.h" #include #include #include // Qt stuff #include #include beChannel::beChannel(QWidget * parent, const QString & channel, beConsole * console) : beMDIWindow(parent, "beChannel", Qt::WDestructiveClose) { m_windowType = beMDIWindow::Channel; m_channel = channel; QString srvname = ""; if(console) { m_pConsole = console; m_pConsole->registerChannel(this); srvname = console->server().hostname(); } QString name = "beChannel "+srvname+" "+channel; setName(name); QStyleSheetItem * item = new QStyleSheetItem( m_pLineView->styleSheet(), "user" ); item->setColor( "black" ); item->setFontWeight( QFont::Bold ); connect ( this, SIGNAL( userInput(const QString &) ), this, SLOT ( say(const QString &) ) ); // append("Welcome to "+channel); m_pListBox->show(); setCaption(channel); show(); } beChannel::~beChannel() { // delete m_pConsole; if(m_pConsole) { qDebug("Leaving "+m_channel); m_pConsole->unregisterChannel(this); qDebug("channel unregistered"); m_pConsole->send("PART :"+m_channel); qDebug("Part cmd sent"); } } QString beChannel::channel() const { return m_channel; } void beChannel::say(const QString & msg) { // should replace me with the username of this program user append("me "+msg); m_pConsole->send("PRIVMSG "+m_channel+" :"+msg); } void beChannel::msg(const QString & user, const QString & msg) { append(""+user+" "+msg); } void beChannel::userJoin(const QString & username) { QString nick_pattern = "[A-Za-z0-9|_\\-{}\\[\\]\\^`@+]+"; // no . append(QString("%1 has joined the channel").arg(username)); QRegExp rx("^("+nick_pattern+")!"); int pos; if( (pos = rx.search(username)) != -1) addUser(rx.cap(1)); else qDebug(tr("Huh ... no username?")); } void beChannel::userLeaved(const QString & username) { QString nick_pattern = "[A-Za-z0-9|_\\-{}\\[\\]\\^`@+]+"; // no . append(QString("%1 has leaved the channel").arg(username)); QRegExp rx("^("+nick_pattern+")!"); int pos; if( (pos = rx.search(username)) != -1) delUser(rx.cap(1)); else qDebug(tr("Huh ... no username?")); } void beChannel::addUser(const QString & username, bool sort) { // bool sort : sort the list box after inserting item // nice to disable if there are a lot of insert, especially when joining // crowded channels... and sorting with beChannel::sortUserList() if(!m_pListBox) { qWarning(tr("Error: beChannel must have a non nul pointer to a QListBox")); return; } // avoids inserting already existing items ( user ) QListBoxItem * item = m_pListBox->findItem(username, Qt::ExactMatch); if(!item) { // qDebug("Inserting "+username); m_pListBox->insertItem(username); if(sort) m_pListBox->sort(true); } else qDebug("Not inserting "+username); } void beChannel::delUser(const QString & username) { if(!m_pListBox) { qWarning(tr("Error: beChannel must have a non nul pointer to a QListBox")); return; } QListBoxItem * item = m_pListBox->findItem(username, Qt::ExactMatch); if(!item) qWarning("This nick ("+username+") doesnt exist... not deleting it"); else { // qDebug("Deleting "+username); m_pListBox->removeItem(m_pListBox->index(item)); } } void beChannel::sortUserList() { m_pListBox->sort(true); } void beChannel::resetUserList() { m_pListBox->clear(); } --Boundary-00=_j25CCxzeOwg/9jl Content-Type: text/x-c++src; charset="us-ascii"; name="beConsole.cpp" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="beConsole.cpp" // beIRC stuff #include "beConsole.h" #include "beChannel.h" // kvirc stuff #define HAVE_CONFIG_H #include "config.h" #include #include #include // QT Stuff #include #include #include #include #include extern KVIRC_API KviIrcServerDataBase * g_pIrcServerDataBase; beConsole::beConsole(QWidget * parent,const char * name) : beMDIWindow(parent,name,Qt::WDestructiveClose) { m_windowType = beMDIWindow::Console; KviIrcNetwork * net = g_pIrcServerDataBase->currentNetwork(); if(net)m_pSrv = net->currentServer(); QString srvname = m_pSrv->hostname(); setCaption(srvname); connect ( this, SIGNAL( userInput(const QString &) ), this, SLOT ( send(const QString &) ) ); connect ( this, SIGNAL( receivedNumericReply(int, const QString &, const QString &)), this, SLOT ( handleNumericReply(int, const QString &, const QString&))); connect ( this, SIGNAL( receivedUserMsg(QString,const QString &,QString) ), this, SLOT ( handleUserMsg(QString, const QString &,QString))); resetOnNameReply = true; // shall I clean the chan user list when I receive a RPL_NAMREPLY ? // inserting all actions that the server may send to us QMap m_actions.insert("PART",PART); } beConsole::~beConsole() { qDebug("Destructor called : closing channels and sending QUIT cmd to serv"); QMap::Iterator it; beChannel* tmp; for ( it = m_channels.begin(); it != m_channels.end(); ++it ) { if(it == 0) break; qDebug("Destroying "+it.data()->channel()); tmp = it.data(); m_channels.remove(it); qDebug("item removed"); delete tmp; qDebug("item destroyed"); } QString cmd = "QUIT :bof\n"; m_pQSocket->writeBlock( cmd.latin1(), cmd.length() ); } bool beConsole::connectToServer() { if(!m_pSrv) { return false; } // \n for new liens // \t for tabs append("Connecting to server..."); m_pQSocket = new QSocket(this); connect( m_pQSocket, SIGNAL( hostFound() ), this, SLOT( hostFound() ) ); connect( m_pQSocket, SIGNAL( connected() ), this, SLOT( connected() ) ); connect( m_pQSocket, SIGNAL( readyRead() ), this, SLOT(socketReadyRead()) ); connect( m_pQSocket, SIGNAL( connectionClosed() ), this, SLOT( disconnected() )); m_pQSocket->connectToHost( m_pSrv->hostname(), m_pSrv->port() ); return true; } void beConsole::hostFound() { append("Host found ..."); } void beConsole::connected() { append("Connected to "+m_pSrv->hostname()+""); QString cmd; cmd = "USER blackeagle 0 "+m_pSrv->hostname()+" :Using beIRC 0.0.11\n"; m_pQSocket->writeBlock( cmd.latin1(), cmd.length() ); cmd = "NICK blackeagle645\n"; m_pQSocket->writeBlock( cmd.latin1(), cmd.length() ); } void beConsole::socketReadyRead() { // append("Socket is ready to read"); while ( m_pQSocket->canReadLine() ) { QString msg = m_pQSocket->readLine(); /* BEGIN removing \n from what the server sends */ msg.truncate(msg.length() - 1); // chop off the \n // QRegExp rxA("(.*)\n$"); // rxA.search( msg ); // append( rxA.cap(1) ); append( msg ); /* END removing \n */ /* BEGIN ping pong fast reply */ QRegExp rx("^PING :([0-9]+)"); int pos; if( (pos = rx.search(msg)) != -1) { QString cmd = "PONG :"+rx.cap(1)+"\n"; m_pQSocket->writeBlock( cmd.latin1(), cmd.length() ); continue; } /* END ping pong fast reply */ // nice one huh ? ;) damn I love regexps ! rx.setPattern(":([A-Za-z0-9|_-`]+)!(~)?([A-Za-z0-9|_-`]+)@([A-Za-z0-9.-]+) PRIVMSG (#[A-Za-z0-9]+) :(.*)"); if( (pos = rx.search(msg)) != -1) { msgForChan(rx.cap(1),rx.cap(5),rx.cap(6)); continue; } QString num_replies_pattern = "[0-9]+"; QString user_cmd_pattern = "JOIN|PART|QUIT|NOTICE|NICK"; // incomplete list // QString nick_pattern = "[A-Za-z0-9|_\-`@+]+"; // no . QString nick_pattern = "[A-Za-z0-9|_\\-{}\\[\\]\\^`@+]+"; QString dns_pattern = "[A-Za-z0-9.\\-]+"; QString user_pattern = nick_pattern+"!~?"+nick_pattern+"@"+dns_pattern; QString channel_pattern = "[A-Za-z0-9~!#\\-_@]+"; QString join_pattern = "("+user_pattern+") JOIN :("+channel_pattern+")"; rx.setPattern(":"+join_pattern); if( (pos = rx.search(msg)) != -1) { userJoinedChan(rx.cap(1),rx.cap(2)); continue; } rx.setPattern(":("+user_pattern+") ("+user_cmd_pattern+") (.*)"); if( (pos = rx.search(msg)) != -1) { emit receivedUserMsg(rx.cap(1),rx.cap(2),rx.cap(3)); continue; } rx.setPattern("^:"+dns_pattern+" ("+num_replies_pattern+") ("+nick_pattern+") (.*)"); if( (pos = rx.search(msg)) != -1) { emit receivedNumericReply(rx.cap(1).toInt(),rx.cap(2),rx.cap(3)); continue; } } } void beConsole::disconnected() { append("Disconnected from server"); } void beConsole::send(const QString & command) { append(""+command+""); // command.append("\n"); QString tmp = command+"\n"; m_pQSocket->writeBlock( tmp.latin1(), tmp.length() ); } KviIrcServer beConsole::server() { return *m_pSrv; } void beConsole::registerChannel(beChannel * channel) { m_channels.insert(channel->channel(),channel); } void beConsole::unregisterChannel(beChannel * channel) { qDebug("unregistering channel"); m_channels.remove(channel->channel()); } void beConsole::msgForChan(const QString & user, const QString & chan, QString msg) { beChannel* channel = m_channels[chan.lower()]; if(!channel) { qDebug("No channel matching found : should create a new one !"); QWidget* workspace = (QWidget*)this->parent()->parent(); if(qstrcmp(workspace->className(),"QWorkspace") != 0) { Q_ASSERT(qstrcmp(workspace->className(),"QWorkspace") == 0); return; } channel = new beChannel(workspace,chan.lower(),this); } // msg.truncate(msg.length() - 1); // removes the \n channel->msg(user,msg); } void beConsole::userJoinedChan(const QString & user, const QString & chan) { qDebug("user joined chan"); beChannel* channel = m_channels[chan.lower()]; if(!channel) { qDebug("No channel matching found : should create a new one !"); QWidget* workspace = (QWidget*)this->parent()->parent(); if(qstrcmp(workspace->className(),"QWorkspace") != 0) { Q_ASSERT(qstrcmp(workspace->className(),"QWorkspace") == 0); return; } channel = new beChannel(workspace,chan.lower(),this); } channel->userJoin(user); } void beConsole::userLeavedChan(const QString & user, const QString & chan) { qDebug("user leaved chan \""+chan+"\""); beChannel* channel = m_channels[chan.lower()]; Q_ASSERT(!channel); // this means that we closed a window without sending PART cmd which is impossible if(channel != 0) channel->userLeaved(user); } void beConsole::handleNumericReply(int num, const QString & user, const QString & args) { switch(num) { case 353: { nameReply(args); return; } case 366: { resetOnNameReply = true; return; } default : { qDebug("Unhandled numeric reply"); return; } } } void beConsole::handleUserMsg(QString user,const QString & action,QString msg) { QString channel_pattern = "#[A-Za-z0-9~!#\\-_@]+"; int pos = 0; UserAction atype = m_actions[action]; switch(atype) { case PART: { qDebug("Part detected.."); // qDebug(msg); QString regexp = "("+channel_pattern+")"; QRegExp rx(regexp); if( (pos = rx.search(msg)) != -1) { userLeavedChan(user,rx.cap(1)); } return; } default : { qDebug("Unhandled user message "+action); return; } } } void beConsole::nameReply(const QString & args) { qDebug("nameReply"); QString channel_pattern = "[A-Za-z0-9~!#\\-_@]+"; QString nick_pattern = "[A-Za-z0-9|_\\-{}\\[\\]\\^`@+]+"; // no spaces in nicks QRegExp rx("=?@? ("+channel_pattern+") :(.*)"); int pos; if( (pos = rx.search(args)) == -1) { qDebug("No matches for nameReply RegExp"); return; } QString chan = rx.cap(1); QString nicks = rx.cap(2); beChannel* channel = m_channels[chan.lower()]; if(!channel) { qDebug("No channel matching found : should create a new one !"); QWidget* workspace = (QWidget*)this->parent()->parent(); if(qstrcmp(workspace->className(),"QWorkspace") != 0) { Q_ASSERT(qstrcmp(workspace->className(),"QWorkspace") == 0); return; } channel = new beChannel(workspace,chan.lower(),this); } if(resetOnNameReply) { channel->resetUserList(); resetOnNameReply = false; } // qDebug("nameReply for channel "+chan.lower()); // qDebug("nameReply - nicks : "+nicks); rx.setPattern(nick_pattern); while ( (pos = rx.search(nicks, pos)) != -1 ) { pos += rx.matchedLength(); channel->addUser(rx.cap(0),false); // do not sort the user list on each insert } channel->sortUserList(); // sorting the user list at the end } --Boundary-00=_j25CCxzeOwg/9jl Content-Type: text/x-chdr; charset="us-ascii"; name="beChannel.h" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="beChannel.h" #ifndef BE_CHANNEL_H #define BE_CHANNEL_H #include "beMDIWindow.h" class QString; class beConsole; class beChannel : public beMDIWindow { friend class beIRC; friend class beConsole; Q_OBJECT Q_PROPERTY( QString m_channel READ channel ); public : beChannel(QWidget * parent = 0, const QString & channel = 0, beConsole * console = 0); ~beChannel(); beLineView* lineview() { return m_pLineView; } QString channel() const; void msg(const QString & user,const QString & msg); void userJoin(const QString & username); void userLeaved(const QString & username); void addUser(const QString & username, bool sort = true); void delUser(const QString & username); private slots: void say(const QString & msg); protected : void sortUserList(); void resetUserList(); private : beConsole* m_pConsole; QString m_channel; }; #endif // ifndef BE_CHANNEL_H --Boundary-00=_j25CCxzeOwg/9jl Content-Type: text/x-chdr; charset="us-ascii"; name="beConsole.h" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="beConsole.h" #ifndef BE_CONSOLE_H #define BE_CONSOLE_H #include "beMDIWindow.h" class KviIrcServer; class QString; class beConsole; class beConsole : beMDIWindow { friend class beIRC; friend class beChannel; Q_OBJECT public : beConsole(QWidget * parent = 0, const char * name = 0); ~beConsole(); KviIrcServer server(); void registerChannel(beChannel * channel); void unregisterChannel(beChannel * channel); enum UserAction { JOIN, PART, QUIT, NICK, MODE }; protected : bool connectToServer(); private slots : virtual void hostFound(); virtual void connected(); virtual void socketReadyRead(); virtual void disconnected(); void send(const QString & command); void msgForChan(const QString & user, const QString & chan, QString msg); void userJoinedChan(const QString & user, const QString & chan); void userLeavedChan(const QString & user, const QString & chan); void handleNumericReply(int num, const QString & user, const QString & args); void handleUserMsg(QString user,const QString & action,QString msg); void nameReply(const QString & args); signals : void receivedNumericReply(int num, const QString & user, const QString & args); void receivedUserMsg(QString user, const QString & action, QString msg); private : KviIrcServer *m_pSrv; // KviProxy * prx; QSocket * m_pQSocket; QMap m_channels; QMap m_actions; bool resetOnNameReply; }; #endif --Boundary-00=_j25CCxzeOwg/9jl Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline >> Visit http://mail.kde.org/mailman/listinfo/kde-devel#unsub to unsubscribe << --Boundary-00=_j25CCxzeOwg/9jl--