/src/sip/jabber/jabber.cpp

http://github.com/tomahawk-player/tomahawk · C++ · 1063 lines · 769 code · 211 blank · 83 comment · 99 complexity · e1bf2498d2b06fcd588b517a8d9b0934 MD5 · raw file

  1. /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2. *
  3. * Copyright 2010-2011, Dominik Schmidt <dev@dominik-schmidt.de>
  4. * Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  5. *
  6. * Tomahawk is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Tomahawk is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "jabber.h"
  20. #include "ui_configwidget.h"
  21. #include "config.h"
  22. #include "tomahawksettings.h"
  23. #include "tomahawksipmessage.h"
  24. #include "tomahawksipmessagefactory.h"
  25. #include <jreen/jid.h>
  26. #include <jreen/capabilities.h>
  27. #include <jreen/vcardupdate.h>
  28. #include <jreen/vcard.h>
  29. #include <jreen/directconnection.h>
  30. #include <jreen/tcpconnection.h>
  31. #include <jreen/softwareversion.h>
  32. #include <jreen/iqreply.h>
  33. #include <qjson/parser.h>
  34. #include <qjson/serializer.h>
  35. #include <QtPlugin>
  36. #include <QStringList>
  37. #include <QDateTime>
  38. #include <QTimer>
  39. #ifndef ENABLE_HEADLESS
  40. #include <QInputDialog>
  41. #include <QLineEdit>
  42. #include <QMessageBox>
  43. #endif
  44. #include <utils/tomahawkutilsgui.h>
  45. #include "utils/logger.h"
  46. using namespace Jreen;
  47. SipPlugin*
  48. JabberFactory::createPlugin( const QString& pluginId )
  49. {
  50. return new JabberPlugin( pluginId.isEmpty() ? generateId() : pluginId );
  51. }
  52. QIcon
  53. JabberFactory::icon() const
  54. {
  55. return QIcon( ":/jabber-icon.png" );
  56. }
  57. JabberPlugin::JabberPlugin( const QString& pluginId )
  58. : SipPlugin( pluginId )
  59. , m_state( Disconnected )
  60. #ifndef ENABLE_HEADLESS
  61. , m_menu( 0 )
  62. , m_xmlConsole( 0 )
  63. #endif
  64. {
  65. qDebug() << Q_FUNC_INFO;
  66. m_currentUsername = accountName();
  67. m_currentServer = readServer();
  68. m_currentPassword = readPassword();
  69. m_currentPort = readPort();
  70. #ifndef ENABLE_HEADLESS
  71. m_configWidget = QWeakPointer< QWidget >( new QWidget );
  72. m_ui = new Ui_JabberConfig;
  73. m_ui->setupUi( m_configWidget.data() );
  74. m_configWidget.data()->setVisible( false );
  75. m_ui->jabberUsername->setText( m_currentUsername );
  76. m_ui->jabberPassword->setText( m_currentPassword );
  77. m_ui->jabberServer->setText( m_currentServer );
  78. m_ui->jabberPort->setValue( m_currentPort );
  79. m_ui->jidExistsLabel->hide();
  80. connect( m_ui->jabberUsername, SIGNAL( textChanged( QString ) ), SLOT( onCheckJidExists( QString ) ) );
  81. #endif
  82. // setup JID object
  83. Jreen::JID jid = Jreen::JID( accountName() );
  84. // general client setup
  85. m_client = new Jreen::Client( jid, m_currentPassword );
  86. setupClientHelper();
  87. m_client->registerPayload(new TomahawkSipMessageFactory);
  88. m_currentResource = QString::fromAscii( "tomahawk%1" ).arg( QString::number( qrand() % 10000 ) );
  89. m_client->setResource( m_currentResource );
  90. #ifndef ENABLE_HEADLESS
  91. // instantiate XmlConsole
  92. if( readXmlConsoleEnabled() )
  93. {
  94. m_xmlConsole = new XmlConsole( m_client );
  95. m_xmlConsole->show();
  96. }
  97. #endif
  98. // add VCardUpdate extension to own presence
  99. m_client->presence().addExtension( new Jreen::VCardUpdate() );
  100. // initaliaze the roster
  101. m_roster = new Jreen::SimpleRoster( m_client );
  102. #ifndef ENABLE_HEADLESS
  103. // initialize the AvatarManager
  104. m_avatarManager = new AvatarManager( m_client );
  105. #endif
  106. // setup disco
  107. m_client->disco()->setSoftwareVersion( "Tomahawk Player", TOMAHAWK_VERSION, CMAKE_SYSTEM );
  108. m_client->disco()->addIdentity( Jreen::Disco::Identity( "client", "type", "tomahawk", "en" ) );
  109. m_client->disco()->addFeature( TOMAHAWK_FEATURE );
  110. // setup caps node
  111. Jreen::Capabilities::Ptr caps = m_client->presence().payload<Jreen::Capabilities>();
  112. caps->setNode( TOMAHAWK_CAP_NODE_NAME );
  113. // print connection parameters
  114. qDebug() << "Our JID set to:" << m_client->jid().full();
  115. qDebug() << "Our Server set to:" << m_client->server();
  116. qDebug() << "Our Port set to" << m_client->port();
  117. // setup slots
  118. connect(m_client, SIGNAL(serverFeaturesReceived(QSet<QString>)), SLOT(onConnect()));
  119. connect(m_client, SIGNAL(disconnected(Jreen::Client::DisconnectReason)), SLOT(onDisconnect(Jreen::Client::DisconnectReason)));
  120. connect(m_client, SIGNAL(messageReceived(Jreen::Message)), SLOT(onNewMessage(Jreen::Message)));
  121. connect(m_client, SIGNAL(iqReceived(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ)));
  122. connect(m_roster, SIGNAL(presenceReceived(Jreen::RosterItem::Ptr,Jreen::Presence)),
  123. SLOT(onPresenceReceived(Jreen::RosterItem::Ptr,Jreen::Presence)));
  124. connect(m_roster, SIGNAL(subscriptionReceived(Jreen::RosterItem::Ptr,Jreen::Presence)),
  125. SLOT(onSubscriptionReceived(Jreen::RosterItem::Ptr,Jreen::Presence)));
  126. #ifndef ENABLE_HEADLESS
  127. connect(m_avatarManager, SIGNAL(newAvatar(QString)), SLOT(onNewAvatar(QString)));
  128. #endif
  129. }
  130. JabberPlugin::~JabberPlugin()
  131. {
  132. delete m_avatarManager;
  133. delete m_roster;
  134. #ifndef ENABLE_HEADLESS
  135. delete m_xmlConsole;
  136. #endif
  137. delete m_client;
  138. delete m_ui;
  139. }
  140. const QString
  141. JabberPlugin::name() const
  142. {
  143. return QString( MYNAME );
  144. }
  145. const QString
  146. JabberPlugin::friendlyName() const
  147. {
  148. return QString( "Jabber" );
  149. }
  150. const QString
  151. JabberPlugin::accountName() const
  152. {
  153. return TomahawkSettings::instance()->value( pluginId() + "/username" ).toString();
  154. }
  155. #ifndef ENABLE_HEADLESS
  156. QMenu*
  157. JabberPlugin::menu()
  158. {
  159. return m_menu;
  160. }
  161. QWidget*
  162. JabberPlugin::configWidget()
  163. {
  164. return m_configWidget.data();
  165. }
  166. QIcon
  167. JabberPlugin::icon() const
  168. {
  169. return QIcon( ":/jabber-icon.png" );
  170. }
  171. #endif
  172. bool
  173. JabberPlugin::connectPlugin( bool startup )
  174. {
  175. Q_UNUSED( startup );
  176. qDebug() << Q_FUNC_INFO;
  177. if(m_client->isConnected())
  178. {
  179. qDebug() << Q_FUNC_INFO << "Already connected to server, not connecting again...";
  180. return true; //FIXME: should i return false here?!
  181. }
  182. qDebug() << "Connecting to the XMPP server..." << m_client->jid().full();
  183. //FIXME: we're badly workarounding some missing reconnection api here, to be fixed soon
  184. QTimer::singleShot( 1000, m_client, SLOT( connectToServer() ) );
  185. if ( m_client->connection() )
  186. connect(m_client->connection(), SIGNAL(error(SocketError)), SLOT(onError(SocketError)));
  187. m_state = Connecting;
  188. emit stateChanged( m_state );
  189. return true;
  190. }
  191. void
  192. JabberPlugin::disconnectPlugin()
  193. {
  194. if (!m_client->isConnected())
  195. {
  196. if ( m_state != Disconnected ) // might be Connecting
  197. {
  198. m_state = Disconnected;
  199. emit stateChanged( m_state );
  200. }
  201. return;
  202. }
  203. //m_roster->deleteLater();
  204. //m_roster = 0;
  205. //m_room->deleteLater();
  206. //m_room = 0;
  207. m_peers.clear();
  208. m_client->disconnectFromServer( true );
  209. m_state = Disconnecting;
  210. emit stateChanged( m_state );
  211. }
  212. void
  213. JabberPlugin::onConnect()
  214. {
  215. // qDebug() << Q_FUNC_INFO;
  216. // update jid resource, servers like gtalk use resource binding and may
  217. // have changed our requested /resource
  218. if ( m_client->jid().resource() != m_currentResource )
  219. {
  220. m_currentResource = m_client->jid().resource();
  221. emit jidChanged( m_client->jid().full() );
  222. }
  223. qDebug() << "Connected to jabber as:" << m_client->jid().full();
  224. // set presence to least valid value
  225. m_client->setPresence(Jreen::Presence::XA, "Got Tomahawk? http://gettomahawk.com", -127);
  226. // set ping timeout to 15 secs (TODO: verify if this works)
  227. m_client->setPingInterval(1000);
  228. // load roster
  229. m_roster->load();
  230. //FIXME: this implementation is totally broken atm, so it's disabled to avoid harm :P
  231. // join MUC with bare jid as nickname
  232. //TODO: make the room a list of rooms and make that configurable
  233. QString mucNickname = QString( "tomahawk@conference.qutim.org/" ).append( QString( m_client->jid().bare() ).replace( "@", "-" ) );
  234. //m_room = new Jreen::MUCRoom(m_client, Jreen::JID( mucNickname ) );
  235. //m_room->setHistorySeconds(0);
  236. //m_room->join();
  237. // treat muc participiants like contacts
  238. //connect( m_room, SIGNAL( messageReceived( Jreen::Message, bool ) ), this, SLOT( onNewMessage( Jreen::Message ) ) );
  239. //connect( m_room, SIGNAL( presenceReceived( Jreen::Presence, const Jreen::MUCRoom::Participant* ) ), this, SLOT( onNewPresence( Jreen::Presence ) ) );
  240. m_state = Connected;
  241. emit stateChanged( m_state );
  242. addMenuHelper();
  243. }
  244. void
  245. JabberPlugin::onDisconnect( Jreen::Client::DisconnectReason reason )
  246. {
  247. qDebug() << Q_FUNC_INFO;
  248. switch( reason )
  249. {
  250. case Jreen::Client::User:
  251. break;
  252. case Jreen::Client::AuthorizationError:
  253. emit error( SipPlugin::AuthError, errorMessage( reason ) );
  254. break;
  255. case Jreen::Client::HostUnknown:
  256. case Jreen::Client::ItemNotFound:
  257. case Jreen::Client::RemoteStreamError:
  258. case Jreen::Client::RemoteConnectionFailed:
  259. case Jreen::Client::InternalServerError:
  260. case Jreen::Client::SystemShutdown:
  261. case Jreen::Client::Conflict:
  262. case Jreen::Client::Unknown:
  263. emit error( SipPlugin::ConnectionError, errorMessage( reason ) );
  264. break;
  265. default:
  266. qDebug() << "Not all Client::DisconnectReasons checked";
  267. Q_ASSERT(false);
  268. break;
  269. }
  270. m_state = Disconnected;
  271. emit stateChanged( m_state );
  272. removeMenuHelper();
  273. Q_FOREACH(const Jreen::JID &peer, m_peers.keys())
  274. {
  275. handlePeerStatus(peer, Jreen::Presence::Unavailable);
  276. }
  277. }
  278. void
  279. JabberPlugin::onError( const Jreen::Connection::SocketError& e )
  280. {
  281. tDebug() << "JABBER error:" << e;
  282. }
  283. QString
  284. JabberPlugin::errorMessage( Jreen::Client::DisconnectReason reason )
  285. {
  286. switch( reason )
  287. {
  288. case Jreen::Client::User:
  289. return tr("User Interaction");
  290. break;
  291. case Jreen::Client::HostUnknown:
  292. return tr("Host is unknown");
  293. break;
  294. case Jreen::Client::ItemNotFound:
  295. return tr("Item not found");
  296. break;
  297. case Jreen::Client::AuthorizationError:
  298. return tr("Authorization Error");
  299. break;
  300. case Jreen::Client::RemoteStreamError:
  301. return tr("Remote Stream Error");
  302. break;
  303. case Jreen::Client::RemoteConnectionFailed:
  304. return tr("Remote Connection failed");
  305. break;
  306. case Jreen::Client::InternalServerError:
  307. return tr("Internal Server Error");
  308. break;
  309. case Jreen::Client::SystemShutdown:
  310. return tr("System shutdown");
  311. break;
  312. case Jreen::Client::Conflict:
  313. return tr("Conflict");
  314. break;
  315. case Jreen::Client::Unknown:
  316. return tr("Unknown");
  317. break;
  318. default:
  319. qDebug() << "Not all Client::DisconnectReasons checked";
  320. Q_ASSERT(false);
  321. break;
  322. }
  323. m_state = Disconnected;
  324. emit stateChanged( m_state );
  325. return QString();
  326. }
  327. void
  328. JabberPlugin::sendMsg(const QString& to, const QString& msg)
  329. {
  330. qDebug() << Q_FUNC_INFO << to << msg;
  331. if ( !m_client ) {
  332. return;
  333. }
  334. /*******************************************************
  335. * Obsolete this by a SipMessage class
  336. */
  337. QJson::Parser parser;
  338. bool ok;
  339. QVariant v = parser.parse( msg.toAscii(), &ok );
  340. if ( !ok || v.type() != QVariant::Map )
  341. {
  342. qDebug() << "Invalid JSON in XMPP msg";
  343. return;
  344. }
  345. QVariantMap m = v.toMap();
  346. /*******************************************************/
  347. TomahawkSipMessage *sipMessage;
  348. if(m["visible"].toBool())
  349. {
  350. sipMessage = new TomahawkSipMessage(m["ip"].toString(),
  351. m["port"].toInt(),
  352. m["uniqname"].toString(),
  353. m["key"].toString()
  354. );
  355. }
  356. else
  357. {
  358. sipMessage = new TomahawkSipMessage();
  359. }
  360. qDebug() << "Send sip messsage to " << to;
  361. Jreen::IQ iq( Jreen::IQ::Set, to );
  362. iq.addExtension( sipMessage );
  363. Jreen::IQReply *reply = m_client->send(iq);
  364. reply->setData(SipMessageSent);
  365. connect(reply, SIGNAL(received(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ)));
  366. }
  367. void
  368. JabberPlugin::broadcastMsg(const QString& msg)
  369. {
  370. qDebug() << Q_FUNC_INFO;
  371. if ( !m_client )
  372. return;
  373. foreach( const Jreen::JID& jid, m_peers.keys() )
  374. {
  375. sendMsg( jid.full(), msg );
  376. }
  377. }
  378. void
  379. JabberPlugin::addContact(const QString& jid, const QString& msg)
  380. {
  381. // Add contact to the Tomahawk group on the roster
  382. QString realJid = jid;
  383. if( !realJid.contains( '@' ) )
  384. realJid += defaultSuffix();
  385. m_roster->subscribe( realJid, msg, realJid, QStringList() << "Tomahawk" );
  386. return;
  387. }
  388. void
  389. JabberPlugin::showAddFriendDialog()
  390. {
  391. #ifndef ENABLE_HEADLESS
  392. bool ok;
  393. QString id = QInputDialog::getText( TomahawkUtils::tomahawkWindow(), tr( "Add Friend" ),
  394. tr( "Enter Jabber ID:" ), QLineEdit::Normal, "", &ok ).trimmed();
  395. if ( !ok )
  396. return;
  397. qDebug() << "Attempting to add jabber contact to roster:" << id;
  398. addContact( id );
  399. #endif
  400. }
  401. QString
  402. JabberPlugin::defaultSuffix() const
  403. {
  404. return "@jabber.org";
  405. }
  406. void
  407. JabberPlugin::showXmlConsole()
  408. {
  409. #ifndef ENABLE_HEADLESS
  410. m_xmlConsole->show();
  411. #endif
  412. }
  413. void
  414. JabberPlugin::checkSettings()
  415. {
  416. bool reconnect = false;
  417. QString username, password, server;
  418. int port;
  419. username = accountName();
  420. password = readPassword();
  421. server = readServer();
  422. port = readPort();
  423. if ( m_currentUsername != username )
  424. {
  425. m_currentUsername = username;
  426. reconnect = true;
  427. }
  428. if ( m_currentPassword != password )
  429. {
  430. m_currentPassword = password;
  431. reconnect = true;
  432. }
  433. if ( m_currentServer != server )
  434. {
  435. m_currentServer = server;
  436. reconnect = true;
  437. }
  438. if ( m_currentPort != readPort() )
  439. {
  440. m_currentPort = port;
  441. reconnect = true;
  442. }
  443. if ( !m_currentUsername.contains( '@' ) )
  444. {
  445. m_currentUsername += defaultSuffix();
  446. TomahawkSettings::instance()->setValue( pluginId() + "/username", m_currentUsername );
  447. }
  448. if ( reconnect )
  449. {
  450. qDebug() << Q_FUNC_INFO << "Reconnecting jreen plugin...";
  451. disconnectPlugin();
  452. setupClientHelper();
  453. qDebug() << Q_FUNC_INFO << "Updated settings";
  454. connectPlugin( false );
  455. }
  456. }
  457. void JabberPlugin::setupClientHelper()
  458. {
  459. Jreen::JID jid = Jreen::JID( m_currentUsername );
  460. m_client->setJID( jid );
  461. m_client->setPassword( m_currentPassword );
  462. if( !m_currentServer.isEmpty() )
  463. {
  464. // set explicit server details
  465. m_client->setServer( m_currentServer );
  466. m_client->setPort( m_currentPort );
  467. }
  468. else
  469. {
  470. // let jreen find out server and port via jdns
  471. m_client->setServer( jid.domain() );
  472. m_client->setPort( -1 );
  473. }
  474. }
  475. void JabberPlugin::addMenuHelper()
  476. {
  477. #ifndef ENABLE_HEADLESS
  478. if( !m_menu )
  479. {
  480. m_menu = new QMenu( QString( "%1 (" ).arg( friendlyName() ).append( accountName() ).append(")" ) );
  481. QAction* addFriendAction = m_menu->addAction( tr( "Add Friend..." ) );
  482. connect( addFriendAction, SIGNAL( triggered() ), this, SLOT( showAddFriendDialog() ) );
  483. if( readXmlConsoleEnabled() )
  484. {
  485. QAction* showXmlConsoleAction = m_menu->addAction( tr( "XML Console...") );
  486. connect( showXmlConsoleAction, SIGNAL( triggered() ), this, SLOT( showXmlConsole() ) );
  487. }
  488. emit addMenu( m_menu );
  489. }
  490. #endif
  491. }
  492. void JabberPlugin::removeMenuHelper()
  493. {
  494. #ifndef ENABLE_HEADLESS
  495. if( m_menu )
  496. {
  497. emit removeMenu( m_menu );
  498. delete m_menu;
  499. m_menu = 0;
  500. }
  501. #endif
  502. }
  503. void JabberPlugin::onNewMessage(const Jreen::Message& message)
  504. {
  505. if ( m_state != Connected )
  506. return;
  507. // qDebug() << Q_FUNC_INFO << "message type" << message.subtype();
  508. QString from = message.from().full();
  509. QString msg = message.body();
  510. if(msg.isEmpty())
  511. return;
  512. if( message.subtype() == Jreen::Message::Error )
  513. {
  514. tDebug() << Q_FUNC_INFO << "Received error message from " << from << ", not answering... (Condition: "
  515. << ( message.error().isNull() ? -1 : message.error()->condition() ) << ")";
  516. return;
  517. }
  518. SipInfo info = SipInfo::fromJson( msg );
  519. if ( !info.isValid() )
  520. {
  521. QString to = from;
  522. QString response = QString( tr("I'm sorry -- I'm just an automatic presence used by Tomahawk Player"
  523. " (http://gettomahawk.com). If you are getting this message, the person you"
  524. " are trying to reach is probably not signed on, so please try again later!") );
  525. // this is not a sip message, so we send it directly through the client
  526. m_client->send( Jreen::Message ( Jreen::Message::Error, Jreen::JID(to), response) );
  527. emit msgReceived( from, msg );
  528. return;
  529. }
  530. qDebug() << Q_FUNC_INFO << "From:" << message.from().full() << ":" << message.body();
  531. emit sipInfoReceived( from, info );
  532. }
  533. void JabberPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr &item, const Jreen::Presence& presence )
  534. {
  535. Q_UNUSED(item);
  536. if ( m_state != Connected )
  537. return;
  538. Jreen::JID jid = presence.from();
  539. QString fulljid( jid.full() );
  540. qDebug() << Q_FUNC_INFO << "* New presence:" << fulljid << presence.subtype();
  541. if( jid == m_client->jid() )
  542. return;
  543. if ( presence.error() ) {
  544. //qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: no" << "presence error";
  545. return;
  546. }
  547. // ignore anyone not Running tomahawk:
  548. Jreen::Capabilities::Ptr caps = presence.payload<Jreen::Capabilities>();
  549. if( caps )
  550. {
  551. qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: maybe" << "caps " << caps->node() << "requesting disco...";
  552. // request disco features
  553. QString node = caps->node() + '#' + caps->ver();
  554. Jreen::IQ featuresIq( Jreen::IQ::Get, jid );
  555. featuresIq.addExtension( new Jreen::Disco::Info( node ) );
  556. Jreen::IQReply *reply = m_client->send(featuresIq);
  557. reply->setData(RequestDisco);
  558. connect(reply, SIGNAL(received(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ)));
  559. }
  560. else if( !caps )
  561. {
  562. // qDebug() << Q_FUNC_INFO << "Running tomahawk: no" << "no caps";
  563. if ( presenceMeansOnline( m_peers[ jid ] ) )
  564. handlePeerStatus( jid, Jreen::Presence::Unavailable );
  565. }
  566. }
  567. void JabberPlugin::onSubscriptionReceived(const Jreen::RosterItem::Ptr& item, const Jreen::Presence& presence)
  568. {
  569. if ( m_state != Connected )
  570. return;
  571. // qDebug() << Q_FUNC_INFO << "presence type:" << presence.subtype();
  572. if(item)
  573. qDebug() << Q_FUNC_INFO << presence.from().full() << "subs" << item->subscription() << "ask" << item->ask();
  574. else
  575. qDebug() << Q_FUNC_INFO << "item empty";
  576. // don't do anything if the contact is already subscribed to us
  577. if( presence.subtype() != Jreen::Presence::Subscribe ||
  578. (
  579. item && (item->subscription() == Jreen::RosterItem::From || item->subscription() == Jreen::RosterItem::Both)
  580. )
  581. )
  582. {
  583. return;
  584. }
  585. // check if the requester is already on the roster
  586. if(item &&
  587. (
  588. item->subscription() == Jreen::RosterItem::To ||
  589. ( item->subscription() == Jreen::RosterItem::None && !item->ask().isEmpty() )
  590. )
  591. )
  592. {
  593. qDebug() << Q_FUNC_INFO << presence.from().bare() << "already on the roster so we assume ack'ing subscription request is okay...";
  594. m_roster->allowSubscription(presence.from(), true);
  595. return;
  596. }
  597. #ifndef ENABLE_HEADLESS
  598. // preparing the confirm box for the user
  599. QMessageBox *confirmBox = new QMessageBox(
  600. QMessageBox::Question,
  601. tr( "Authorize User" ),
  602. QString( tr( "Do you want to grant <b>%1</b> access to your Collection?" ) ).arg(presence.from().bare()),
  603. QMessageBox::Yes | QMessageBox::No,
  604. TomahawkUtils::tomahawkWindow()
  605. );
  606. // add confirmBox to m_subscriptionConfirmBoxes
  607. m_subscriptionConfirmBoxes.insert( presence.from(), confirmBox );
  608. // display the box and wait for the answer
  609. confirmBox->open( this, SLOT( onSubscriptionRequestConfirmed( int ) ) );
  610. #endif
  611. }
  612. void
  613. JabberPlugin::onSubscriptionRequestConfirmed( int result )
  614. {
  615. #ifndef ENABLE_HEADLESS
  616. qDebug() << Q_FUNC_INFO << result;
  617. QList< QMessageBox* > confirmBoxes = m_subscriptionConfirmBoxes.values();
  618. Jreen::JID jid;
  619. foreach( QMessageBox* currentBox, confirmBoxes )
  620. {
  621. if( currentBox == sender() )
  622. {
  623. jid = m_subscriptionConfirmBoxes.key( currentBox );
  624. }
  625. }
  626. // we got an answer, deleting the box
  627. m_subscriptionConfirmBoxes.remove( jid );
  628. sender()->deleteLater();
  629. QMessageBox::StandardButton allowSubscription = static_cast<QMessageBox::StandardButton>( result );
  630. if ( allowSubscription == QMessageBox::Yes )
  631. {
  632. qDebug() << Q_FUNC_INFO << jid.bare() << "accepted by user, adding to roster";
  633. addContact(jid, "");
  634. }
  635. else
  636. {
  637. qDebug() << Q_FUNC_INFO << jid.bare() << "declined by user";
  638. }
  639. m_roster->allowSubscription( jid, allowSubscription == QMessageBox::Yes );
  640. #endif
  641. }
  642. void JabberPlugin::onNewIq(const Jreen::IQ& iq)
  643. {
  644. if ( m_state != Connected )
  645. return;
  646. Jreen::IQReply *reply = qobject_cast<Jreen::IQReply*>(sender());
  647. int context = reply ? reply->data().toInt() : NoContext;
  648. if( context == RequestDisco )
  649. {
  650. // qDebug() << Q_FUNC_INFO << "Received disco IQ...";
  651. Jreen::Disco::Info *discoInfo = iq.payload<Jreen::Disco::Info>().data();
  652. if(!discoInfo)
  653. return;
  654. iq.accept();
  655. Jreen::JID jid = iq.from();
  656. Jreen::DataForm::Ptr form = discoInfo->form();
  657. if(discoInfo->features().contains( TOMAHAWK_FEATURE ))
  658. {
  659. qDebug() << Q_FUNC_INFO << jid.full() << "Running tomahawk/feature enabled: yes";
  660. // the actual presence doesn't matter, it just needs to be "online"
  661. handlePeerStatus( jid, Jreen::Presence::Available );
  662. }
  663. }
  664. else if(context == RequestVersion)
  665. {
  666. Jreen::SoftwareVersion::Ptr softwareVersion = iq.payload<Jreen::SoftwareVersion>();
  667. if( softwareVersion )
  668. {
  669. QString versionString = QString("%1 %2 %3").arg( softwareVersion->name(), softwareVersion->os(), softwareVersion->version() );
  670. qDebug() << Q_FUNC_INFO << "Received software version for " << iq.from().full() << ":" << versionString;
  671. emit softwareVersionReceived( iq.from().full(), versionString );
  672. }
  673. }
  674. else if(context == RequestedDisco)
  675. {
  676. qDebug() << "Sent IQ(Set), what should be happening here?";
  677. }
  678. else if( context == SipMessageSent )
  679. {
  680. qDebug() << "Sent SipMessage... what now?!";
  681. }
  682. /*else if(context == RequestedVCard )
  683. {
  684. qDebug() << "Requested VCard... what now?!";
  685. }*/
  686. else
  687. {
  688. TomahawkSipMessage::Ptr sipMessage = iq.payload<TomahawkSipMessage>();
  689. if(sipMessage)
  690. {
  691. iq.accept();
  692. qDebug() << Q_FUNC_INFO << "Got SipMessage ..."
  693. << "ip" << sipMessage->ip() << "port" << sipMessage->port() << "uniqname" << sipMessage->uniqname() << "key" << sipMessage->key() << "visible" << sipMessage->visible();
  694. SipInfo info;
  695. info.setVisible( sipMessage->visible() );
  696. if( sipMessage->visible() )
  697. {
  698. QHostInfo hi;
  699. hi.setHostName( sipMessage->ip() );
  700. info.setHost( hi );
  701. info.setPort( sipMessage->port() );
  702. info.setUniqname( sipMessage->uniqname() );
  703. info.setKey( sipMessage->key() );
  704. }
  705. Q_ASSERT( info.isValid() );
  706. qDebug() << Q_FUNC_INFO << "From:" << iq.from().full() << ":" << info;
  707. emit sipInfoReceived( iq.from().full(), info );
  708. }
  709. }
  710. }
  711. bool JabberPlugin::presenceMeansOnline(Jreen::Presence::Type p)
  712. {
  713. switch(p)
  714. {
  715. case Jreen::Presence::Invalid:
  716. case Jreen::Presence::Unavailable:
  717. case Jreen::Presence::Error:
  718. return false;
  719. break;
  720. default:
  721. return true;
  722. }
  723. }
  724. void JabberPlugin::handlePeerStatus(const Jreen::JID& jid, Jreen::Presence::Type presenceType)
  725. {
  726. QString fulljid = jid.full();
  727. // "going offline" event
  728. if ( !presenceMeansOnline( presenceType ) &&
  729. ( !m_peers.contains( jid ) ||
  730. presenceMeansOnline( m_peers.value( jid ) )
  731. )
  732. )
  733. {
  734. m_peers[ jid ] = presenceType;
  735. qDebug() << Q_FUNC_INFO << "* Peer goes offline:" << fulljid;
  736. emit peerOffline( fulljid );
  737. return;
  738. }
  739. // "coming online" event
  740. if( presenceMeansOnline( presenceType ) &&
  741. ( !m_peers.contains( jid ) ||
  742. !presenceMeansOnline( m_peers.value( jid ) )
  743. )
  744. )
  745. {
  746. m_peers[ jid ] = presenceType;
  747. qDebug() << Q_FUNC_INFO << "* Peer goes online:" << fulljid;
  748. emit peerOnline( fulljid );
  749. #ifndef ENABLE_HEADLESS
  750. if(!m_avatarManager->avatar(jid.bare()).isNull())
  751. onNewAvatar( jid.bare() );
  752. #endif
  753. // request software version
  754. Jreen::IQ versionIq( Jreen::IQ::Get, jid );
  755. versionIq.addExtension( new Jreen::SoftwareVersion() );
  756. Jreen::IQReply *reply = m_client->send(versionIq);
  757. reply->setData(RequestVersion);
  758. connect(reply, SIGNAL(received(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ)));
  759. return;
  760. }
  761. //qDebug() << "Updating presence data for" << fulljid;
  762. m_peers[ jid ] = presenceType;
  763. }
  764. void JabberPlugin::onNewAvatar(const QString& jid)
  765. {
  766. #ifndef ENABLE_HEADLESS
  767. // qDebug() << Q_FUNC_INFO << jid;
  768. if ( m_state != Connected )
  769. return;
  770. Q_ASSERT(!m_avatarManager->avatar( jid ).isNull());
  771. // find peers for the jid
  772. QList<Jreen::JID> peers = m_peers.keys();
  773. foreach(const Jreen::JID &peer, peers)
  774. {
  775. if( peer.bare() == jid )
  776. {
  777. emit avatarReceived ( peer.full(), m_avatarManager->avatar( jid ) );
  778. }
  779. }
  780. if( jid == m_client->jid().bare() )
  781. // own avatar
  782. emit avatarReceived ( m_avatarManager->avatar( jid ) );
  783. else
  784. // someone else's avatar
  785. emit avatarReceived ( jid, m_avatarManager->avatar( jid ) );
  786. #endif
  787. }
  788. bool
  789. JabberPlugin::readXmlConsoleEnabled()
  790. {
  791. return TomahawkSettings::instance()->value( pluginId() + "/xmlconsole", QVariant( false ) ).toBool();
  792. }
  793. QString
  794. JabberPlugin::readPassword()
  795. {
  796. return TomahawkSettings::instance()->value( pluginId() + "/password" ).toString();
  797. }
  798. int
  799. JabberPlugin::readPort()
  800. {
  801. return TomahawkSettings::instance()->value( pluginId() + "/port", 5222 ).toInt();
  802. }
  803. QString
  804. JabberPlugin::readServer()
  805. {
  806. return TomahawkSettings::instance()->value( pluginId() + "/server" ).toString();
  807. }
  808. void
  809. JabberPlugin::onCheckJidExists( QString jid )
  810. {
  811. for ( int i=0; i<TomahawkSettings::instance()->sipPlugins().count(); i++ )
  812. {
  813. QString savedUsername = TomahawkSettings::instance()->value(
  814. TomahawkSettings::instance()->sipPlugins().at( i ) + "/username" ).toString();
  815. QStringList splitUserName = TomahawkSettings::instance()->value(
  816. TomahawkSettings::instance()->sipPlugins().at( i ) + "/username" ).toString().split("@");
  817. QString server = TomahawkSettings::instance()->value(
  818. TomahawkSettings::instance()->sipPlugins().at( i ) + "/server" ).toString();
  819. if ( ( savedUsername == jid || splitUserName.contains( jid ) ) &&
  820. server == m_ui->jabberServer->text() && !jid.trimmed().isEmpty() )
  821. {
  822. m_ui->jidExistsLabel->show();
  823. // the already jid exists
  824. emit dataError( true );
  825. return;
  826. }
  827. }
  828. m_ui->jidExistsLabel->hide();
  829. emit dataError( false );
  830. }
  831. void
  832. JabberPlugin::saveConfig()
  833. {
  834. TomahawkSettings::instance()->setValue( pluginId() + "/username", m_ui->jabberUsername->text() );
  835. TomahawkSettings::instance()->setValue( pluginId() + "/password", m_ui->jabberPassword->text() );
  836. TomahawkSettings::instance()->setValue( pluginId() + "/port", m_ui->jabberPort->value() );
  837. TomahawkSettings::instance()->setValue( pluginId() + "/server", m_ui->jabberServer->text() );
  838. checkSettings();
  839. }
  840. void
  841. JabberPlugin::deletePlugin()
  842. {
  843. TomahawkSettings::instance()->remove( pluginId() );
  844. }
  845. SipPlugin::ConnectionState
  846. JabberPlugin::connectionState() const
  847. {
  848. return m_state;
  849. }
  850. #ifndef GOOGLE_WRAPPER
  851. Q_EXPORT_PLUGIN2( sipfactory, JabberFactory )
  852. #endif