Import release 2.0alpha2

This commit is contained in:
Mario Fetka
2008-08-10 11:56:25 +00:00
parent 47cc8f14fa
commit 8b3dac7ce6
303 changed files with 78286 additions and 49595 deletions
+378 -89
View File
@@ -21,6 +21,11 @@
#include "networkwindow.h"
#include "../network/mimemessage.h"
#include "../network/msnnotificationconnection.h"
#include "../network/p2pmessage.h"
#include "../utils/kmessconfig.h"
#include <QFile>
#include <QRegExp>
#include <QSize>
@@ -34,39 +39,52 @@
#include <KMessageBox>
#include <KTabWidget>
#include <KTextBrowser>
#include "../network/p2pmessage.h"
#include <kdeversion.h>
// Declare the instance
NetworkWindow * NetworkWindow::instance_(0);
// Constructor
NetworkWindow::NetworkWindow( QWidget *parent )
: KDialog( parent, Qt::Dialog ) // Explicitly set the window type to disable the destructive close behavior
, connectionTabs_(0)
, Ui::NetworkWindow()
{
// Set up the dialog and its buttons
setButtons( Close | User1 | User2 | User3 );
setButtons( Close | User1 | User2 );
setDefaultButton( Close );
setCaption( i18n("Network Window") );
restoreDialogSize( KGlobal::config()->group("NetworkWindow") );
restoreDialogSize( KMessConfig::instance()->getGlobalConfig( "NetworkWindow" ) );
// Load the ui file in a main qwidget
QWidget *mainWidget = new QWidget(this);
setupUi( mainWidget );
setMainWidget( mainWidget );
// Set up the behavior of the Tab Widget
#if KDE_IS_VERSION(4,1,0)
connectionTabs_->setCloseButtonEnabled( true );
#else
connectionTabs_->setHoverCloseButton( true );
#endif
connect( connectionTabs_, SIGNAL( closeRequest(QWidget*) ), this, SLOT( closeTab(QWidget*) ) );
connect( connectionTabs_, SIGNAL( currentChanged(int) ), this, SLOT( slotUpdateWidgets(int) ) );
// Set up the behavior of the Send button
connect( sendCommandButton_, SIGNAL( released() ), this, SLOT( slotSendCommand() ) );
// Name our custom buttons and setup their behavior
setButtonText( User1, i18n("S&ave tab") );
setButtonText( User2, i18n("C&lear tab") );
setButtonText( User3, i18n("Cl&ose tab") );
setButtonIcon( User1, KIcon("document-save") );
setButtonIcon( User2, KIcon("edit-clear-list") );
connect( this, SIGNAL( user1Clicked() ), this, SLOT( saveCurrentTab() ) );
connect( this, SIGNAL( user2Clicked() ), this, SLOT( clearCurrentTab() ) );
connect( this, SIGNAL( user3Clicked() ), this, SLOT( closeCurrentTab() ) );
// Create the window's contents: a tab widget with a tab for each connection
connectionTabs_ = new KTabWidget( this );
// Add it as main widget with enough space to a good number of lines at once
setMainWidget(connectionTabs_);
setInitialSize( QSize(800, 600) );
// Set the default state of the ui widgets
sendStandardCmdRadio_->setChecked( true );
}
@@ -74,7 +92,7 @@ NetworkWindow::NetworkWindow( QWidget *parent )
// Destructor
NetworkWindow::~NetworkWindow()
{
KConfigGroup group = KGlobal::config()->group("NetworkWindow");
KConfigGroup group = KMessConfig::instance()->getGlobalConfig( "NetworkWindow" );
saveDialogSize( group );
foreach( ConnectionEntry *entry, connectionViews_.values() )
@@ -101,6 +119,9 @@ NetworkWindow::~NetworkWindow()
entry->logView->append( html );
entry->lastMessage = now;
// Update the widgets for the currently visible tab
slotUpdateWidgets();
}
@@ -142,7 +163,7 @@ NetworkWindow::~NetworkWindow()
ConnectionEntry *entry = getConnectionEntry(connection);
entry->logView->append("<p style='margin:0; color: #C2C2C2'>the connection was closed<br>" + getTime() + "</p>\n");
entry->lastMessage = QDateTime::currentDateTime();
entry->isClosed = true;
// // Unregister the connection, so new attempts from the same class generate a new object.
// connectionViews_.remove(browser);
}
@@ -152,67 +173,152 @@ NetworkWindow::~NetworkWindow()
// Return a log description for a standard command.
QString NetworkWindow::describeCommand(const QString &command)
{
if( command.startsWith("VER ") )
QString firstPart = command.left(3); // command[0] in normal code.
int errorCode = firstPart.toInt();
if( errorCode != 0 )
{
return formatDescription("Protocol version negotiation");
}
else if ( command.startsWith("CVR ") )
{
return formatDescription("Application version exchange");
}
else if ( command.startsWith("XFR ") )
{
return formatDescription("Server transfer request");
}
else if ( command.startsWith("USR ") )
{
return formatDescription("User login information");
}
else if ( command.startsWith("SYN ") )
{
return formatDescription("Contactlist sync request");
}
else if ( command.startsWith("CHG ") )
{
return formatDescription("Client status message (change of online state, client capabilities or msn object)");
}
else if ( command.startsWith("CHL ") )
{
return formatDescription("Challenge query");
}
else if ( command.startsWith("IRO ") )
{
return formatDescription("Contact already in chat");
}
else if ( command.startsWith("CAL ") )
{
return formatDescription("Calling a contact to join chat");
}
else if ( command.startsWith("RNG ") )
{
return formatDescription("Invitation for a chat");
}
else if ( command.startsWith("ANS ") )
{
return formatDescription("Chat invitation answer with user login information");
}
else if ( command.startsWith("JOI ") )
{
return formatDescription("Contact joins chat");
}
else if ( command.startsWith("FIL ") )
{
return formatDescription("Indicates the size of the entire file");
}
else if ( command.startsWith("TFR ") )
{
return formatDescription("Start of file transfer");
switch( errorCode )
{
// Command is a 3 digit error code.
case 200: return formatDescription("Error: Invalid syntax");
case 201: return formatDescription("Error: Invalid parameter");
case 205: return formatDescription("Error: Invalid principal; not an MSN account");
case 206: return formatDescription("Error: Domain name missing");
case 207: return formatDescription("Error: Already logged in");
case 208: return formatDescription("Error: Invalid principal; not an MSN account");
case 209: return formatDescription("Error: Nickname change illegal");
case 210: return formatDescription("Error: Principal list full");
case 213: return formatDescription("Error: Invalid rename request");
case 215: return formatDescription("Error: Principal already on list");
case 216: return formatDescription("Error: Principal not on list");
case 217: return formatDescription("Error: Principal not online");
case 218: return formatDescription("Error: Already in this mode");
case 219: return formatDescription("Error: Principal is in the opposite list");
case 223: return formatDescription("Error: Too many groups");
case 224: return formatDescription("Error: Invalid group");
case 225: return formatDescription("Error: Principal not in group");
case 227: return formatDescription("Error: Group not empty");
case 228: return formatDescription("Error: Group with same name already exists");
case 229: return formatDescription("Error: Group name too long");
case 230: return formatDescription("Error: Cannot remove group zero");
case 231: return formatDescription("Error: Invalid group");
case 240: return formatDescription("Error: Empty domain");
case 280: return formatDescription("Error: Switchboard server failed");
case 281: return formatDescription("Error: Transfer to switchboard failed");
case 282: return formatDescription("Error: P2P header error");
case 300: return formatDescription("Error: Required field missing");
case 302: return formatDescription("Error: Not logged in");
case 402: // same as 403
case 403: return formatDescription("Error: Error accessing contact list");
case 420: return formatDescription("Error: Invalid account permissions"); // CVR with unofficial client, non beta service tester
case 500: return formatDescription("Error: Service Temporarily Unavailable");
case 501: return formatDescription("Error: Database server error");
case 502: return formatDescription("Error: Protocol command is disabled");
case 510: return formatDescription("Error: File operation failed");
case 511: return formatDescription("Error: Account is banned");
case 520: return formatDescription("Error: Memory allocation failed");
case 540: return formatDescription("Error: Challenge response failed");
case 600: return formatDescription("Error: Server is busy");
case 601: return formatDescription("Error: Server is unavailable");
case 602: return formatDescription("Error: Peer nameserver is down");
case 603: return formatDescription("Error: Database connection failed");
case 604: return formatDescription("Error: Server is going down");
case 605: return formatDescription("Error: Server unavailable");
case 700: return formatDescription("Error: Connection failed");
case 710: return formatDescription("Error: Bad command parameter");
case 711: return formatDescription("Error: Write is blocking");
case 712: return formatDescription("Error: Session is overloaded");
case 713: return formatDescription("Error: Opening chat sessions too fast");
case 714: return formatDescription("Error: Too many chat sessions open");
case 715: return formatDescription("Error: Unexpected command value");
case 717: return formatDescription("Error: Bad friend file");
case 731: return formatDescription("Error: Not expected");
case 800: return formatDescription("Error: Changing names too fast");
case 911: return formatDescription("Error: Authentication ticket was incorrect");
case 913: return formatDescription("Error: not allowed when hidden");
case 923: return formatDescription("Error: Kids' Passport without parental consent");
case 924: return formatDescription("Error: passport account not verified yet");
case 928: return formatDescription("Error: bad ticket");
case 931: return formatDescription("Error: account not on this server"); // if using a cached NS instead of the main dispatch point.
case 900:
case 912:
case 918:
case 919:
case 921:
case 922: return formatDescription("Error: Server too busy");
case 914:
case 915:
case 916: return formatDescription("Error: Server unavailable");
case 917: return formatDescription("Error: authentication failed");
default: return formatDescription("Error, type is unknown!");
}
}
else
{
// return QString::null;
return formatDescription( QString::null ); // always add time.
if( firstPart == "VER" )
{
return formatDescription("Protocol version negotiation");
}
else if ( firstPart == "CVR" )
{
return formatDescription("Application version exchange");
}
else if ( firstPart == "XFR" )
{
return formatDescription("Server transfer request");
}
else if ( firstPart == "USR" )
{
return formatDescription("User login information");
}
else if ( firstPart == "SYN" )
{
return formatDescription("Contactlist sync request");
}
else if ( firstPart == "CHG" )
{
return formatDescription("Client status message (change of online state, client capabilities or msn object)");
}
else if ( firstPart == "CHL" )
{
return formatDescription("Challenge query");
}
else if ( firstPart == "IRO" )
{
return formatDescription("Contact already in chat");
}
else if ( firstPart == "CAL" )
{
return formatDescription("Calling a contact to join chat");
}
else if ( firstPart == "RNG" )
{
return formatDescription("Invitation for a chat");
}
else if ( firstPart == "ANS" )
{
return formatDescription("Chat invitation answer with user login information");
}
else if ( firstPart == "JOI" )
{
return formatDescription("Contact joins chat");
}
else if ( firstPart == "FIL" )
{
return formatDescription("Indicates the size of the entire file");
}
else if ( firstPart == "TFR" )
{
return formatDescription("Start of file transfer");
}
}
// Default
// return QString::null;
return formatDescription( QString::null ); // always add time.
}
@@ -663,7 +769,23 @@ NetworkWindow::~NetworkWindow()
else
{
// Whole message is in utf-8
// remove last <br> because KTextBrowser::append() already adds it.
// First hide things we don't want to log.
if( entry->type == TYPE_HTTP )
{
// Hide passwords from the passport login, if they are included in the message
int passStart = utf8Message.indexOf("<wsse:Password>");
if( passStart != -1 )
{
passStart += 15; // size of xml tag
int passEnd = utf8Message.indexOf("</wsse:Password>", passStart);
int passLen = ( passEnd - passStart );
utf8Message = utf8Message.replace( passStart, passLen, QString( passLen, '*' ) );
}
}
// Convert to HTML.
// Remove last <br> because KTextBrowser::append() already adds it.
logMessage = formatString( utf8Message );
logMessage = logMessage.replace(QRegExp("<br>$"), QString::null);
@@ -767,6 +889,7 @@ NetworkWindow::~NetworkWindow()
// The message a utf-8 (MSNSLP) payload if the session id is zero.
bool hasSlpPayload = ( sessionId == 0 && dataSize > 0 );
int dataEnd = ( p2pDataStart + dataSize );
int realEnd = ( message.size() );
if( hasSlpPayload )
{
// See if the SLP body is terminated with a final null character (should be).
@@ -777,7 +900,7 @@ NetworkWindow::~NetworkWindow()
}
// Display the SLP body
QString slpMessage = QString::fromUtf8( message.data() + p2pDataStart, qMin( dataSize, (quint32) message.size() - p2pDataStart ) );
QString slpMessage = QString::fromUtf8( message.data() + p2pDataStart, qMin( dataSize, (quint32) qMin( dataEnd, realEnd ) - p2pDataStart ) );
logMessage += "\n<br>" + formatString(slpMessage);
// Add message footer
@@ -885,9 +1008,12 @@ NetworkWindow::~NetworkWindow()
connectionViews_.insert( connection, entry );
// Add new tab
connectionTabs_->addTab( entry->logView, connection->objectName() );
connectionTabs_->addTab( entry->logView, KIcon( "edit-select-all" ), connection->objectName() );
}
// Initialize new connections and reinitialize old ones as open
entry->isClosed = false;
return entry;
}
@@ -907,7 +1033,7 @@ NetworkWindow::~NetworkWindow()
ConnectionEntry *entry = getConnectionEntry(connection);
// If empty, set the initial label. Otherwise add a IRC-like rename message
if( entry->logView->toHtml().length() == 0 )
if( entry->type == TYPE_UNKNOWN )
{
connectionTabs_->setTabText( connectionTabs_->indexOf( entry->logView ), title );
entry->logView->append("<p><font color='#C2C2C2'>Log started by " + QString(connection->objectName()) + "</font></p>");
@@ -923,7 +1049,7 @@ NetworkWindow::~NetworkWindow()
// Show the window if there are connection logs to show
void NetworkWindow::show()
{
if( connectionTabs_ == 0 || connectionTabs_->count() < 1 )
if( connectionTabs_->count() < 1 )
{
KMessageBox::error( this, i18n("No connections are present.\nCannot open the Network Window.") );
return;
@@ -937,7 +1063,7 @@ NetworkWindow::~NetworkWindow()
// The 'save tab' button was pressed.
void NetworkWindow::saveCurrentTab()
{
if( connectionTabs_ == 0 )
if( connectionTabs_->currentWidget() == 0 )
return;
QString path;
@@ -980,7 +1106,7 @@ NetworkWindow::~NetworkWindow()
// The 'clear tab' button was pressed.
void NetworkWindow::clearCurrentTab()
{
if( connectionTabs_ == 0 )
if( connectionTabs_->currentWidget() == 0 )
return;
static_cast<KTextBrowser *>( connectionTabs_->currentWidget() )->clear();
@@ -988,23 +1114,16 @@ NetworkWindow::~NetworkWindow()
// The 'close tab' button was pressed.
void NetworkWindow::closeCurrentTab()
// A 'close tab' button was pressed.
void NetworkWindow::closeTab( QWidget *removedWidget )
{
if( connectionTabs_ == 0 )
return;
if( connectionTabs_->currentIndex() == 0 )
if( connectionTabs_->indexOf( removedWidget ) == 0 )
{
KMessageBox::information( this, i18n("Cannot close the main connection tab.") );
return;
}
// Remove the current page from the tab widget
QWidget *removedWidget = connectionTabs_->currentWidget();
connectionTabs_->removeTab( connectionTabs_->currentIndex() );
// Also remove it from the list of views
// Remove the widget from the list of views
QHashIterator<void*,ConnectionEntry*>it( connectionViews_ );
while( it.hasNext() )
{
@@ -1037,5 +1156,175 @@ NetworkWindow::~NetworkWindow()
}
// A tab was selected.
void NetworkWindow::slotUpdateWidgets( int selectedTab )
{
bool enable = false;
// Automatically obtain the tab index instead of getting it as a parameter
if( selectedTab < -1 )
{
selectedTab = connectionTabs_->currentIndex();
}
// If there are open tabs, find out which one is selected.
// If there are none, just disable the command sending group
if( selectedTab != -1 )
{
QWidget *currentWidget = connectionTabs_->currentWidget();
QHashIterator<void*,ConnectionEntry*> it( connectionViews_ );
// Iterate through all connections to find whether the current one is connected or not
while( it.hasNext() )
{
it.next();
if( it.value()->logView == currentWidget )
{
// The active tab's connection is active, enable the widgets
if( ! it.value()->isClosed )
{
enable = true;
}
break;
}
}
}
commandSendingGroup_->setEnabled( enable );
}
// Send a command
void NetworkWindow::slotSendCommand()
{
// Get the text fields' text
QString command( commandEdit_->text().toUpper() );
QString payload( payloadEdit_->toPlainText() );
// Empty commands can't be sent
if( command.isEmpty() || connectionTabs_->currentIndex() == -1 )
{
commandEdit_->setFocus();
return;
}
// Warn the developer about what he or she is doing.
int result = KMessageBox::warningContinueCancel( this,
i18n( "Sending commands to the server is a risky operation.<br />"
"If you don't know how exactly send messages to the servers,"
"you could be lucky and just get disconnected, or <i>you may"
"incur in more serious consequences</i>.<br />"
"You have been warned!<br />"
"<b>Do you want to continue sending this message?</b>" ),
i18n( "Network Window" ),
KStandardGuiItem::cont(),
KStandardGuiItem::cancel(),
"sendServerCommandWarning" );
// Bail out, just in time
if( result != KMessageBox::Continue )
{
return;
}
// The developer knows what he or she is doing, send the command
// Replace all newlines with the kind used by the server
payload.replace( QRegExp( "\r?\n" ), "\r\n" );
// Empty payloads can, and will be replaced with a single newline
if( payload.isEmpty() )
{
payload = "\r\n";
}
else if( ! payload.endsWith( "\r\n" ) )
{
// Warn the developer that the payloads must end with a newline
int result = KMessageBox::warningYesNo( this,
i18n( "The payload you are trying to send does not end with the "
"required newline ('\\r\\n')!<br />"
"Do you want KMess to add it for you?" ),
i18n( "Network Window" ),
KStandardGuiItem::yes(),
KStandardGuiItem::no(),
"noPayloadWarning" );
// Append the missing newline to the payload
if( result == KMessageBox::Yes )
{
payload.append( "\r\n" );
}
}
// Find the currently active tab
QWidget *currentWidget = connectionTabs_->currentWidget();
QHashIterator<void*,ConnectionEntry*> it( connectionViews_ );
void *connection;
const ConnectionEntry *entry;
// Iterate through all connections to find out which one's tab is selected in the UI
while( it.hasNext() )
{
it.next();
// Save the entry, we'll need it later
entry = it.value();
// If the current tab is for this connection..
if( entry->logView == currentWidget )
{
// .. disallow sending commands to disconnected connections
if( entry->isClosed )
{
commandEdit_->setFocus();
return;
}
// ..save the tab's connection to send commands there
connection = it.key();
break;
}
}
// Send the command to the right type of connection
MsnNotificationConnection *nsConnection;
switch( entry->type )
{
case TYPE_NS:
case TYPE_SB:
nsConnection = static_cast<MsnNotificationConnection*>( connection );
// Disallow sending commands to disconnected connections
if( ! nsConnection->isConnected() )
{
return;
}
// Send the type of command the developer wants
if( sendStandardCmdRadio_->isChecked() )
{
nsConnection->sendCommand( command, payload );
}
else
{
nsConnection->sendMimeMessage( MsnNotificationConnection::ACK_ALWAYS, MimeMessage( payload ) );
}
return;
// TODO: Enable sending commands to these types of connections.
case TYPE_UNKNOWN:
case TYPE_FTP:
case TYPE_FTP_RAW:
case TYPE_DC:
case TYPE_HTTP:
default:
KMessageBox::error( 0, i18n( "Cannot send commands to this kind of connection!" ) );
return;
}
}
#include "networkwindow.moc"
#endif // KMESS_NETWORK_WINDOW