Show invite menu in wlm chat window immediately
[kdenetwork.git] / kopete / plugins / otr / otrplugin.cpp
blobc80d1679112d8a71260c782d7440df9f28cda62a
1 /*************************************************************************
2 * Copyright <2007> <Michael Zanetti> <michael_zanetti@gmx.net> *
3 * *
4 * This program is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU General Public License as *
6 * published by the Free Software Foundation; either version 2 of *
7 * the License or (at your option) version 3 or any later version *
8 * accepted by the membership of KDE e.V. (or its successor approved *
9 * by the membership of KDE e.V.), which shall act as a proxy *
10 * defined in Section 14 of version 3 of the license. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 *************************************************************************/
21 #include "otrplugin.h"
22 #include "otrguiclient.h"
23 #include "otrlchatinterface.h"
24 #include "kopete_otr.h"
26 #include <qtimer.h>
27 #include <qregexp.h>
28 #include <qfile.h>
29 #include <qcolor.h>
31 #include <kdebug.h>
32 #include <kaction.h>
33 #include <kconfig.h>
34 #include <kgenericfactory.h>
35 #include <kselectaction.h>
36 #include <kactioncollection.h>
38 #include <kopetemetacontact.h>
39 #include <kopetecontactlist.h>
40 #include <kopetechatsessionmanager.h>
41 #include <kopetesimplemessagehandler.h>
42 #include <kopeteuiglobal.h>
43 #include <kopetecontact.h>
44 #include <kopetemessage.h>
45 #include <kopeteaccount.h>
46 #include <kopeteaccountmanager.h>
47 #include <kopetemessageevent.h>
48 #include <kopeteprotocol.h>
49 #include <ui/kopeteview.h>
52 /**
53 * @author Michael Zanetti
57 K_PLUGIN_FACTORY ( OTRPluginFactory, registerPlugin<OTRPlugin>(); )
58 K_EXPORT_PLUGIN ( OTRPluginFactory ( "kopete_otr" ) )
61 OTRPlugin::OTRPlugin ( QObject *parent, const QVariantList &/*args*/ )
62 : Kopete::Plugin ( OTRPluginFactory::componentData(), parent )
65 kDebug(14318) << "OTR Plugin loading...";
67 if( !pluginStatic_ )
68 pluginStatic_=this;
70 m_inboundHandler = new OtrMessageHandlerFactory(this);
72 connect( Kopete::ChatSessionManager::self(), SIGNAL( aboutToSend( Kopete::Message & ) ),
73 SLOT( slotOutgoingMessage( Kopete::Message & ) ) );
75 connect( Kopete::ChatSessionManager::self(), SIGNAL( chatSessionCreated( Kopete::ChatSession * ) ),
76 this, SLOT( slotNewChatSessionWindow( Kopete::ChatSession * ) ) );
78 connect( this, SIGNAL( settingsChanged() ), this, SLOT( slotSettingsChanged() ) );
82 //initialize the otrlib and create the interface object
83 otrlChatInterface = OtrlChatInterface::self();
84 otrlChatInterface->setPlugin(this);
87 // Checking file Permissions
88 OtrlChatInterface::self()->checkFilePermissions( QString( KGlobal::dirs()->saveLocation( "data", "kopete_otr/", true ) ) + "privkeys" );
89 OtrlChatInterface::self()->checkFilePermissions( QString( KGlobal::dirs()->saveLocation( "data", "kopete_otr/", true ) ) + "fingerprints" );
91 //setting the policy
92 slotSettingsChanged();
94 //adding menu to contaclists menubar and contacts popup menu
95 otrPolicyMenu = new KSelectAction( KIcon("object-locked"), i18nc( "@item:inmenu", "&OTR Policy" ), this );
96 actionCollection()->addAction( "otr_policy", otrPolicyMenu );
98 KAction *separatorAction = new KAction( otrPolicyMenu );
99 separatorAction->setSeparator( true );
101 otrPolicyMenu->addAction( i18nc( "@item:inmenu Use the default encryption mode specified in settings dialog", "&Default") );
102 otrPolicyMenu->addAction( separatorAction );
103 otrPolicyMenu->addAction( i18nc( "@item:inmenu Always encrypt messages", "Al&ways" ) );
104 otrPolicyMenu->addAction( i18nc( "@item:inmenu Use the opportunistic encryption mode", "&Opportunistic") );
105 otrPolicyMenu->addAction( i18nc( "@item:inmenu Use the manual encryption mode", "&Manual") );
106 otrPolicyMenu->addAction( i18nc( "@item:inmenu Never encrypt messages", "Ne&ver") );
108 otrPolicyMenu->setEnabled( false );
110 connect( otrPolicyMenu, SIGNAL( triggered( int ) ), this, SLOT( slotSetPolicy() ) );
111 connect( Kopete::ContactList::self(), SIGNAL( metaContactSelected( bool ) ), this, SLOT( slotSelectionChanged( bool ) ) );
113 setXMLFile( "otrui.rc" );
115 //Add GUI action to all already existing kmm
116 // (if the plugin is launched when kopete already runing)
117 QList<Kopete::ChatSession*> sessions =
118 Kopete::ChatSessionManager::self()->sessions();
119 QListIterator<Kopete::ChatSession*> it(sessions);
120 while (it.hasNext()){
121 slotNewChatSessionWindow(it.next());
125 OTRPlugin::~OTRPlugin()
127 delete m_inboundHandler;
128 pluginStatic_ = 0L;
129 kDebug(14318) << "Exiting OTR plugin";
133 OTRPlugin* OTRPlugin::plugin()
135 return pluginStatic_ ;
138 OTRPlugin* OTRPlugin::pluginStatic_ = 0L;
141 void OTRPlugin::slotNewChatSessionWindow( Kopete::ChatSession *KMM )
143 //Check if there is another user in the session.
144 //If not it could be a Jabber-MUC
145 //If there is more than one member it is a MUC
146 // Also don't add the Button on an IRC window!
147 if( KMM->members().count() == 1 && (KMM->protocol()) && ( KMM->protocol()->pluginId() != "IRCProtocol" ) ){
148 new OtrGUIClient( KMM );
153 void OTRPlugin::slotOutgoingMessage( Kopete::Message& msg )
155 if( msg.direction() == Kopete::Message::Outbound ){
156 QString plainBody = msg.plainBody();
157 QString cacheBody = msg.plainBody();
158 QString accountId = msg.manager()->account()->accountId();
159 Kopete::Contact *contact = msg.to().first();
161 QString *encBody = otrlChatInterface->encryptMessage( &plainBody, accountId, msg.manager()->account()->protocol()->displayName(), contact->contactId(), msg.manager() );
162 msg.setPlainBody( *encBody );
163 msg.setType(Kopete::Message::TypeNormal);
164 if( !msg.plainBody().isEmpty() ){
165 messageCache.insert( *encBody, cacheBody );
166 } else {
167 messageCache.insert( "!OTR:MsgDelByOTR", cacheBody );
172 void OTRPlugin::slotEnableOtr( Kopete::ChatSession *session, bool enable ){
175 if( enable ){
176 QString policy = session->members().first()->metaContact()->pluginData( OTRPlugin::plugin(), "otr_policy" );
177 bool noerr;
178 KopeteOtrKcfg::self()->readConfig();
179 if( policy.toInt( &noerr, 10 ) == 4 || ( policy.toInt( &noerr, 10 ) == 0 && KopeteOtrKcfg::self()->rbNever() ) ){
180 Kopete::Message msg( session->account()->myself(), session->members());
181 msg.setPlainBody( i18nc( "@info:status", "Your policy settings do not allow encrypted sessions to this contact." ));
182 msg.setDirection( Kopete::Message::Internal);
183 session->appendMessage( msg );
184 } else {
185 QString body = otrlChatInterface->getDefaultQuery( session->account()->accountId() );
186 Kopete::Message msg1( session->account()->myself(), session->members().first());
187 msg1.setPlainBody( QString( body ) );
188 msg1.setDirection( Kopete::Message::Outbound );
189 if( otrlChatInterface->privState( session ) > 0 ){
190 body = i18nc( "@info:status", "Attempting to refresh the OTR session with <b>%1</b>...", otrlChatInterface->formatContact( session->members().first()->contactId()) );
191 } else {
192 body = i18nc( "@info:status", "Attempting to start a private OTR session with <b>%1</b>...", otrlChatInterface->formatContact( session->members().first()->contactId() ));
194 Kopete::Message msg2( session->account()->myself(), session->members().first());
195 msg2.setHtmlBody( body );
196 msg2.setDirection( Kopete::Message::Internal );
198 session->sendMessage( msg1 );
199 session->appendMessage( msg2 );
201 } else {
202 otrlChatInterface->disconnectSession( session );
207 void OTRPlugin::slotVerifyFingerprint( Kopete::ChatSession *session ){
208 otrlChatInterface->verifyFingerprint( session );
211 void OTRPlugin::slotSettingsChanged(){
213 KopeteOtrKcfg::self()->readConfig();
214 if( KopeteOtrKcfg::self()->rbAlways() ){
215 otrlChatInterface->setPolicy( OTRL_POLICY_ALWAYS );
216 } else if( KopeteOtrKcfg::self()->rbOpportunistic() ){
217 otrlChatInterface->setPolicy( OTRL_POLICY_OPPORTUNISTIC );
218 } else if( KopeteOtrKcfg::self()->rbManual() ){
219 otrlChatInterface->setPolicy( OTRL_POLICY_MANUAL );
220 } else if( KopeteOtrKcfg::self()->rbNever() ){
221 otrlChatInterface->setPolicy( OTRL_POLICY_NEVER );
222 } else {
223 otrlChatInterface->setPolicy( OTRL_POLICY_DEFAULT );
227 void OTRPlugin::emitGoneSecure( Kopete::ChatSession *session, int status){
228 emit goneSecure( session, status );
231 QMap<QString, QString> OTRPlugin::getMessageCache(){
232 return messageCache;
235 void OtrMessageHandler::handleMessage( Kopete::MessageEvent *event ){
236 if ( !plugin ){
237 MessageHandler::handleMessage( event );
238 return;
241 Kopete::Message msg = event->message();
242 // Kopete::ChatSession *session = msg.manager();
243 QMap<QString, QString> messageCache = plugin->getMessageCache();
245 if( msg.direction() == Kopete::Message::Inbound ){
246 QString body = msg.plainBody();
247 QString accountId = msg.manager()->account()->accountId();
248 QString contactId = msg.from()->contactId();
249 int retValue = OtrlChatInterface::self()->decryptMessage( &body, accountId, msg.manager()->account()->protocol()->displayName(), contactId, msg.manager() );
250 msg.setHtmlBody( body );
251 if( (retValue == 2) | OtrlChatInterface::self()->shouldDiscard( msg.plainBody() ) ){
252 // internal OTR message
253 event->discard();
254 return;
255 } else if(retValue == 1){
256 // plaintext message. Proceed with next plugin
257 MessageHandler::handleMessage( event );
258 return;
260 } else if( msg.direction() == Kopete::Message::Outbound ){
261 if( messageCache.contains( msg.plainBody() ) ){
262 msg.setPlainBody( messageCache[msg.plainBody()] );
263 messageCache.remove( messageCache[msg.plainBody()] );
264 if(messageCache.count() > 5) messageCache.clear();
266 // Check if Message is an OTR message. Should it be discarded or shown?
267 if( OtrlChatInterface::self()->shouldDiscard( msg.plainBody() ) ){
268 event->discard();
269 kDebug(14318) << "OTR: discarding message";
270 return;
272 // If the message is sent while a Finished state libotr deletes the messagetext.
273 // This prevents the empty message from being shown in our chatwindow
274 if( msg.plainBody().isEmpty() ){
275 event->discard();
276 if(messageCache.contains("!OTR:MsgDelByOTR")){
277 msg.setPlainBody(messageCache["!OTR:MsgDelByOTR"]);
278 msg.manager()->view()->setCurrentMessage(msg);
279 messageCache.remove("!OTR:MsgDelByOTR");
281 return;
285 event->setMessage( msg );
287 MessageHandler::handleMessage( event );
291 void OTRPlugin::slotSelectionChanged( bool single){
292 otrPolicyMenu->setEnabled( single );
294 if ( !single )
295 return;
297 Kopete::MetaContact *metaContact = Kopete::ContactList::self()->selectedMetaContacts().first();
299 QString policy = metaContact->pluginData( this, "otr_policy" );
301 bool noerr;
302 if ( !policy.isEmpty() && policy != "null" )
303 otrPolicyMenu->setCurrentItem( policy.toInt( &noerr, 10 ) + 1); // +1 because of the Separator
304 else
305 otrPolicyMenu->setCurrentItem( 0 );
309 void OTRPlugin::slotSetPolicy(){
310 kDebug(14318) << "Setting contact policy";
311 Kopete::MetaContact *metaContact = Kopete::ContactList::self()->selectedMetaContacts().first();
312 if( metaContact ){
313 metaContact->setPluginData( this, "otr_policy", QString::number( otrPolicyMenu->currentItem() - 1 ) ); // -1 because of the Separator
315 kDebug(14318) << "Selected policy: " << otrPolicyMenu->currentItem();
318 void OTRPlugin::slotSecuritySate(Kopete::ChatSession *session, int state)
320 emitGoneSecure(session, state);
323 #include "otrplugin.moc"
325 // vim: set noet ts=4 sts=4 sw=4: