1 /*************************************************************************
2 * Copyright <2007> <Michael Zanetti> <michael_zanetti@gmx.net> *
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. *
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. *
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"
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>
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...";
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" );
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
;
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
);
167 messageCache
.insert( "!OTR:MsgDelByOTR", cacheBody
);
172 void OTRPlugin::slotEnableOtr( Kopete::ChatSession
*session
, bool enable
){
176 QString policy
= session
->members().first()->metaContact()->pluginData( OTRPlugin::plugin(), "otr_policy" );
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
);
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()) );
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
);
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
);
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(){
235 void OtrMessageHandler::handleMessage( Kopete::MessageEvent
*event
){
237 MessageHandler::handleMessage( event
);
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
255 } else if(retValue
== 1){
256 // plaintext message. Proceed with next plugin
257 MessageHandler::handleMessage( event
);
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() ) ){
269 kDebug(14318) << "OTR: discarding message";
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() ){
276 if(messageCache
.contains("!OTR:MsgDelByOTR")){
277 msg
.setPlainBody(messageCache
["!OTR:MsgDelByOTR"]);
278 msg
.manager()->view()->setCurrentMessage(msg
);
279 messageCache
.remove("!OTR:MsgDelByOTR");
285 event
->setMessage( msg
);
287 MessageHandler::handleMessage( event
);
291 void OTRPlugin::slotSelectionChanged( bool single
){
292 otrPolicyMenu
->setEnabled( single
);
297 Kopete::MetaContact
*metaContact
= Kopete::ContactList::self()->selectedMetaContacts().first();
299 QString policy
= metaContact
->pluginData( this, "otr_policy" );
302 if ( !policy
.isEmpty() && policy
!= "null" )
303 otrPolicyMenu
->setCurrentItem( policy
.toInt( &noerr
, 10 ) + 1); // +1 because of the Separator
305 otrPolicyMenu
->setCurrentItem( 0 );
309 void OTRPlugin::slotSetPolicy(){
310 kDebug(14318) << "Setting contact policy";
311 Kopete::MetaContact
*metaContact
= Kopete::ContactList::self()->selectedMetaContacts().first();
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: