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 *************************************************************************/
22 * @author Michael Zanetti
25 #include "otrlchatinterface.h"
26 #include "privkeypopup.h"
28 #include <kopetechatsession.h>
29 #include <kopeteaccount.h>
30 #include <kopeteaccountmanager.h>
31 #include <kopetemessageevent.h>
32 #include <kopetecontactlist.h>
33 #include <kopetemetacontact.h>
34 #include <ui/kopeteview.h>
35 #include <kopeteprotocol.h>
36 #include <kopetecontact.h>
39 #include <kmessagebox.h>
40 #include <kstandarddirs.h>
42 #include <kpassivepopup.h>
43 #include <kpushbutton.h>
47 #include <qnamespace.h>
48 #include <qeventloop.h>
49 #include <qapplication.h>
51 #include <qfileinfo.h>
55 #include <sys/types.h>
59 OtrlChatInterface
*OtrlChatInterface::mSelf
= 0;
60 static OtrlUserState userstate
;
61 static OtrlPolicy confPolicy
;
62 //static void *updateContextList = 0;
63 static Kopete::Plugin
*chatPlugin
= 0;
65 /***************************** Gui_UI_Ops for libotr **********************************/
66 static OtrlPolicy
policy(void *opdata
, ConnContext
*context
){
70 Kopete::ChatSession
*session
= ((Kopete::ChatSession
*)opdata
);
73 // Disable OTR for IRC
74 if( session
->protocol()->pluginId() == "IRCProtocol" ){
75 // kdDebug() << "Disabling OTR for: " << session->protocol()->pluginId() << endl;
76 return OTRL_POLICY_NEVER
;
79 policy
= session
->members().first()->metaContact()->pluginData( chatPlugin
, QString("otr_policy") );
80 // kdDebug() << "Metacontact policy is: " << policy.toInt( &noerr, 10) << endl;
81 switch( policy
.toInt( &noerr
, 10 ) ){
83 return OTRL_POLICY_ALWAYS
;
85 return OTRL_POLICY_OPPORTUNISTIC
;
87 return OTRL_POLICY_MANUAL
;
89 return OTRL_POLICY_NEVER
;
95 static void create_privkey(void *opdata
, const char *accountname
, const char *protocol
){
96 Kopete::ChatSession
*session
= ((Kopete::ChatSession
*)opdata
);
98 if( !session
->view() ){
101 PrivKeyPopup
*popup
= new PrivKeyPopup( session
->view()->mainWidget() );
103 popup
->setCloseLock( true );
105 KeyGenThread
*keyGenThread
= new KeyGenThread ( accountname
, protocol
);
106 keyGenThread
->start();
107 while( !keyGenThread
->wait(100) ){
108 qApp
->processEvents(QEventLoop::ExcludeUserInputEvents
| QEventLoop::ExcludeSocketNotifiers
, 100);
111 popup
->setCloseLock( false );
115 static int is_logged_in(void *opdata
, const char *accountname
, const char *protocol
, const char *recipient
){
117 Q_UNUSED(accountname
)
120 Kopete::ChatSession
*session
= ((Kopete::ChatSession
*)opdata
);
121 Kopete::ContactPtrList list
= session
->members();
122 for( int i
= 0; i
< list
.size(); i
++ ){
123 if( list
.at(i
)->contactId().compare( recipient
) == 0 ){
124 Kopete::OnlineStatus status
= session
->contactOnlineStatus( list
.at(i
) );
125 if( status
== Kopete::OnlineStatus::Unknown
){
127 } else if( status
== Kopete::OnlineStatus::Offline
){
137 static void inject_message( void *opdata
, const char *accountname
, const char *protocol
, const char *recipient
, const char *message
){
139 Q_UNUSED(accountname
)
142 // kDebug(14318) << "Sending message:" << message;
144 Kopete::ChatSession
*session
= ((Kopete::ChatSession
*)opdata
);
145 Kopete::ContactPtrList list
= session
->members();
146 for( int i
= 0; i
< list
.size(); i
++ ){
147 if( list
.at(i
)->contactId().compare( recipient
) == 0 ){
148 Kopete::Message
msg( session
->account()->myself(), list
.at(i
) );
149 msg
.setPlainBody( QString( message
) );
150 msg
.setDirection( Kopete::Message::Outbound
);
151 session
->sendMessage( msg
);
157 static void notify(void *opdata
, OtrlNotifyLevel level
, const char *accountname
, const char *protocol
, const char *username
, const char *title
, const char *primary
, const char *secondary
){
161 Q_UNUSED(accountname
)
165 KMessageBox::information(NULL
, QString( primary
) + QString( secondary
), QString( title
) );
168 static int display_otr_message( void *opdata
, const char *accountname
, const char *protocol
, const char *username
, const char *message
){
170 Q_UNUSED(accountname
)
173 Kopete::ChatSession
*session
= ((Kopete::ChatSession
*)opdata
);
174 Kopete::ContactPtrList list
= session
->members();
175 for( int i
= 0; i
< list
.size(); i
++ ){
176 if( list
.at(i
)->contactId().compare( username
) == 0 ){
177 Kopete::Message
msg( session
->members().first(), session
->account()->myself() );
178 msg
.setHtmlBody( QString( message
) );
179 msg
.setDirection( Kopete::Message::Internal
);
180 session
->appendMessage( msg
);
187 static void update_context_list(void *opdata
){
192 static const char *protocol_name(void *opdata
, const char *protocol
){
198 // kdDebug() << "protocol_name called" << endl;
202 static void protocol_name_free(void *opdata
, const char *protocol_name
){
206 Q_UNUSED(protocol_name
)
208 // kdDebug() << "protocol_name_free called" << endl;
211 static void new_fingerprint(void *opdata
, OtrlUserState us
, const char *accountname
, const char *protocol
, const char *username
, unsigned char fingerprint
[20]){
214 Q_UNUSED(accountname
)
217 Q_UNUSED(fingerprint
)
219 // kdDebug() << "Received a new Fingerprint" << endl;
220 Kopete::ChatSession
*session
= ((Kopete::ChatSession
*)opdata
);
221 Kopete::Message
msg( session
->members().first(), session
->account()->myself() );
222 msg
.setHtmlBody( i18n("<b>Received a new fingerprint from <a>%1</a>. You should authenticate this contact.</b>", session
->members().first()->contactId()) );
223 msg
.setDirection( Kopete::Message::Internal
);
224 session
->appendMessage( msg
);
227 static void write_fingerprints(void *opdata
){
231 // kdDebug() << "Writing fingerprints" << endl;
232 QString savePath
= QString(KGlobal::dirs()->saveLocation("data", "kopete_otr/", true )) + "fingerprints";
233 otrl_privkey_write_fingerprints( userstate
, savePath
.toLocal8Bit() );
236 static void gone_secure(void *opdata
, ConnContext
*context
){
237 // kdDebug() << "gone secure" << endl;
238 Kopete::ChatSession
*session
= ((Kopete::ChatSession
*)opdata
);
240 if( context
->active_fingerprint
->trust
&& context
->active_fingerprint
->trust
[0] ){
241 Kopete::Message
msg( session
->members().first(), session
->account()->myself() );
242 msg
.setHtmlBody( i18n("<b>Private OTR session started.</b>") );
243 msg
.setDirection( Kopete::Message::Internal
);
244 session
->appendMessage( msg
);
245 OtrlChatInterface::self()->emitGoneSecure(session
, 2);
247 Kopete::Message
msg( session
->members().first(), session
->account()->myself() );
248 msg
.setHtmlBody( i18n("<b>Unverified OTR session started.</b>") );
249 msg
.setDirection( Kopete::Message::Internal
);
250 session
->appendMessage( msg
);
251 OtrlChatInterface::self()->emitGoneSecure( ((Kopete::ChatSession
*)opdata
), 1 );
255 static void gone_insecure(void *opdata
, ConnContext
*context
){
259 // kdDebug() << "gone insecure" << endl;
260 OtrlChatInterface::self()->emitGoneSecure(((Kopete::ChatSession
*)opdata
), 0);
261 Kopete::ChatSession
*session
= ((Kopete::ChatSession
*)opdata
);
262 Kopete::Message
msg( session
->members().first(), session
->account()->myself() );
263 msg
.setHtmlBody( i18n("<b>OTR Session ended. Note that the conversation is now insecure.</b>") );
264 msg
.setDirection( Kopete::Message::Internal
);
265 session
->appendMessage( msg
);
268 static void still_secure(void *opdata
, ConnContext
*context
, int is_reply
){
272 // kdDebug() << "still secure" << endl;
273 Kopete::ChatSession
*session
= ((Kopete::ChatSession
*)opdata
);
274 Kopete::Message
msg( session
->members().first(), session
->account()->myself() );
275 msg
.setHtmlBody( i18n("<b>OTR connection refreshed successfully.</b>") );
276 msg
.setDirection( Kopete::Message::Internal
);
277 session
->appendMessage( msg
);
279 if( context
->active_fingerprint
->trust
&& context
->active_fingerprint
->trust
[0] ){
280 OtrlChatInterface::self()->emitGoneSecure( session
, 2);
282 OtrlChatInterface::self()->emitGoneSecure( session
, 1);
286 static void log_message(void *opdata
, const char *message
){
290 kDebug(14318) << "libotr: "<< message
;
293 static int max_message_size(void *opdata
, ConnContext
*context
){
294 Kopete::ChatSession
*session
= ((Kopete::ChatSession
*)opdata
);
298 kDebug(14318) << session
->protocol()->pluginId();
300 if( session
->protocol()->pluginId() == "MSNProtocol" ){
302 } else if( session
->protocol()->pluginId() == "ICQProtocol" ){
304 } else if( session
->protocol()->pluginId() == "AIMProtocol" ){
306 } else if( session
->protocol()->pluginId() == "YahooProtocol" ){
310 // Jabber doesn't need fragmentation. Return 0 to disable.
311 // GaduGadu seems to not need fragmentation too.
315 static OtrlMessageAppOps ui_ops
= {
336 /*********************** Gui_UI_Ops finished *************************/
339 /*********************** Constructor/Destructor **********************/
341 OtrlChatInterface::OtrlChatInterface(){
345 userstate
= otrl_userstate_create();
346 QString readPath
= QString(KGlobal::dirs()->saveLocation("data", "kopete_otr/", true )) + "privkeys";
347 otrl_privkey_read( userstate
, readPath
.toLocal8Bit() );
350 QString savePath
= QString(KGlobal::dirs()->saveLocation("data", "kopete_otr/", true )) + "fingerprints";
351 otrl_privkey_read_fingerprints(userstate
, savePath
.toLocal8Bit(), NULL
, NULL
);
355 OtrlChatInterface::~ OtrlChatInterface(){
356 otrl_userstate_free(userstate
);
360 KDE_EXPORT OtrlChatInterface
*OtrlChatInterface::self(){
362 new OtrlChatInterface();
367 KDE_EXPORT
void OtrlChatInterface::setPlugin( Kopete::Plugin
*plugin
){
371 /********************* Chat section ***************************/
373 OtrlUserState
OtrlChatInterface::getUserstate(){
378 KDE_EXPORT
int OtrlChatInterface::decryptMessage( QString
*msg
, const QString
&accountId
,
379 const QString
&protocol
, const QString
&contactId
, Kopete::ChatSession
*chatSession
){
382 char *newMessage
= NULL
;
383 OtrlTLV
*tlvs
= NULL
;
385 ConnContext
*context
;
386 NextExpectedSMP nextMsg
;
388 ignoremessage
= otrl_message_receiving( userstate
, &ui_ops
, chatSession
, accountId
.toLocal8Bit(), protocol
.toLocal8Bit(), contactId
.toLocal8Bit(), msg
->toLocal8Bit(), &newMessage
, &tlvs
, NULL
, NULL
);
390 tlv
= otrl_tlv_find(tlvs
, OTRL_TLV_DISCONNECTED
);
392 Kopete::Message
msg( chatSession
->members().first(), chatSession
->account()->myself() );
393 msg
.setHtmlBody( i18n("<b>%1</b> has ended the OTR session. You should do the same.",chatSession
->members().first()->contactId() ) );
394 msg
.setDirection( Kopete::Message::Internal
);
395 chatSession
->appendMessage( msg
);
396 OtrlChatInterface::self()->emitGoneSecure( chatSession
, 3 );
399 context
= otrl_context_find( userstate
, contactId
.toLocal8Bit(), accountId
.toLocal8Bit(), protocol
.toLocal8Bit(), 0, NULL
, NULL
, NULL
);
401 nextMsg
= context
->smstate
->nextExpected
;
404 if (context
->smstate
->sm_prog_state
== OTRL_SMP_PROG_CHEATED
) {
405 abortSMP(context
, chatSession
);
406 context
->smstate
->nextExpected
= OTRL_SMP_EXPECT1
;
407 context
->smstate
->sm_prog_state
= OTRL_SMP_PROG_OK
;
409 tlv
= otrl_tlv_find(tlvs
, OTRL_TLV_SMP1Q
);
411 if (nextMsg
!= OTRL_SMP_EXPECT1
){
412 kDebug(14318) << "Abording SMP: 1Q";
413 abortSMP( context
, chatSession
);
415 kDebug(14318) << "Update SMP state: 1Q";
416 new AuthenticationWizard( chatSession
->view()->mainWidget(), context
, chatSession
, false, QString((char*)tlvs
->data
) );
420 tlv
= otrl_tlv_find(tlvs
, OTRL_TLV_SMP1
);
422 if (nextMsg
!= OTRL_SMP_EXPECT1
){
423 kDebug(14318) << "Abording SMP: 1";
424 abortSMP( context
, chatSession
);
426 kDebug(14318) << "Update SMP state: 1 ";
427 new AuthenticationWizard( chatSession
->view()->mainWidget(), context
, chatSession
, false );
430 tlv
= otrl_tlv_find(tlvs
, OTRL_TLV_SMP2
);
432 if (nextMsg
!= OTRL_SMP_EXPECT2
){
433 kDebug(14318) << "Abording SMP: 2";
434 abortSMP( context
, chatSession
);
436 kDebug(14318) << "Update SMP state: 2 -> 3";
437 AuthenticationWizard::findWizard(chatSession
)->nextState();
438 context
->smstate
->nextExpected
= OTRL_SMP_EXPECT4
;
441 tlv
= otrl_tlv_find(tlvs
, OTRL_TLV_SMP3
);
443 if (nextMsg
!= OTRL_SMP_EXPECT3
){
444 kDebug(14318) << "Abording SMP: 3";
445 abortSMP( context
, chatSession
);
447 kDebug(14318) << "SMP: 3";
448 if(context
->smstate
->sm_prog_state
== OTRL_SMP_PROG_SUCCEEDED
){
449 if (context
->active_fingerprint
->trust
&& context
->active_fingerprint
->trust
[0]) {
450 AuthenticationWizard::findWizard(chatSession
)->finished(true, true);
451 kDebug(14318) << "trust found";
452 Kopete::Message
msg( chatSession
->members().first(), chatSession
->account()->myself() );
453 msg
.setHtmlBody( i18n("Authentication with <b>%1</b> successful. The conversation is now secure.", formatContact(chatSession
->members().first()->contactId())));
454 msg
.setDirection( Kopete::Message::Internal
);
455 chatSession
->appendMessage( msg
);
456 OtrlChatInterface::self()->emitGoneSecure( chatSession
, 2 );
458 AuthenticationWizard::findWizard(chatSession
)->finished(true, false);
459 kDebug(14318) << "trust _NOT_ found";
460 Kopete::Message
msg( chatSession
->members().first(), chatSession
->account()->myself() );
461 msg
.setHtmlBody( i18n("<b>%1</b> has successfully authenticated you. You may want to authenticate this contact as well by asking your own question.", formatContact(chatSession
->members().first()->contactId())));
462 msg
.setDirection( Kopete::Message::Internal
);
463 chatSession
->appendMessage( msg
);
464 OtrlChatInterface::self()->emitGoneSecure( chatSession
, 1 );
468 AuthenticationWizard::findWizard(chatSession
)->finished(false, false);
469 Kopete::Message
msg( chatSession
->members().first(), chatSession
->account()->myself() );
470 msg
.setHtmlBody( i18n("Authentication with <b>%1</b> failed. The conversation is now insecure.", formatContact(chatSession
->members().first()->contactId())));
471 msg
.setDirection( Kopete::Message::Internal
);
472 chatSession
->appendMessage( msg
);
473 OtrlChatInterface::self()->emitGoneSecure( chatSession
, 1 );
476 context
->smstate
->nextExpected
= OTRL_SMP_EXPECT1
;
479 tlv
= otrl_tlv_find(tlvs
, OTRL_TLV_SMP4
);
481 if (nextMsg
!= OTRL_SMP_EXPECT4
) {
482 kDebug(14318) << "Abording SMP: 4";
483 abortSMP( context
, chatSession
);
485 kDebug(14318) << "SMP: 4";
486 if (context
->active_fingerprint
->trust
&& context
->active_fingerprint
->trust
[0]) {
487 AuthenticationWizard::findWizard(chatSession
)->finished(true, true);
488 kDebug(14318) << "trust found";
489 Kopete::Message
msg( chatSession
->members().first(), chatSession
->account()->myself() );
490 msg
.setHtmlBody( i18n("<b>Authentication successful. The conversation is now secure.</b>") );
491 msg
.setDirection( Kopete::Message::Internal
);
492 chatSession
->appendMessage( msg
);
493 OtrlChatInterface::self()->emitGoneSecure( chatSession
, 2 );
495 AuthenticationWizard::findWizard(chatSession
)->finished(false, false);
496 kDebug(14318) << "trust _NOT_ found";
497 Kopete::Message
msg( chatSession
->members().first(), chatSession
->account()->myself() );
498 msg
.setHtmlBody( i18n("<b>Authentication failed. Note that the conversation is now insecure.</b>") );
499 msg
.setDirection( Kopete::Message::Internal
);
500 chatSession
->appendMessage( msg
);
501 OtrlChatInterface::self()->emitGoneSecure( chatSession
, 1 );
503 context
->smstate
->nextExpected
= OTRL_SMP_EXPECT1
;
506 tlv
= otrl_tlv_find(tlvs
, OTRL_TLV_SMP_ABORT
);
508 Kopete::Message
msg( chatSession
->members().first(), chatSession
->account()->myself() );
509 msg
.setHtmlBody( i18n("<b>Authentication error.</b>") );
510 msg
.setDirection( Kopete::Message::Internal
);
511 chatSession
->appendMessage( msg
);
512 context
->smstate
->nextExpected
= OTRL_SMP_EXPECT1
;
519 // message is now decrypted or is a Plaintext message and ready to deliver
520 if( !ignoremessage
){
521 // message is decrypted
522 if( newMessage
!= NULL
){
523 *msg
= QString::fromUtf8(newMessage
);
524 otrl_message_free( newMessage
);
525 msg
->replace( QString('\n'), QString("<br>") );
526 return 0; // message is decrypted and ready to deliver
528 return 1; // message was a plaintext message. Better not touching it :)
531 return 2; // internal OTR message. Ignore it.
534 KDE_EXPORT QString
*OtrlChatInterface::encryptMessage( QString
*msg
, const QString
&accountId
,
535 const QString
&protocol
, const QString
&contactId
, Kopete::ChatSession
*chatSession
){
540 if( otrl_proto_message_type( msg
->toLocal8Bit() ) == OTRL_MSGTYPE_NOTOTR
){
541 msg
->replace( QString('<'), QString("<") );
542 err
= otrl_message_sending( userstate
, &ui_ops
, chatSession
, accountId
.toLocal8Bit(), protocol
.toLocal8Bit(), contactId
.toLocal8Bit(), msg
->toUtf8(), NULL
, &newMessage
, NULL
, NULL
);
545 *msg
= i18n("Encryption error");
546 } else if( newMessage
){
548 /* Fragment the message if needed */
549 /* If fragmentation is needed libotr will send out all fragments but the last one. */
550 ConnContext
*context
= otrl_context_find(userstate
, contactId
.toLocal8Bit(), accountId
.toLocal8Bit(), protocol
.toLocal8Bit(), 0, NULL
, NULL
, NULL
);
552 //kDebug(14318) << "message to be sent out: " << newMessage;
554 err
= otrl_message_fragment_and_send(&ui_ops
, chatSession
, context
, newMessage
,
555 OTRL_FRAGMENT_SEND_ALL_BUT_LAST
, &fragment
);
557 kDebug(14318) << "fragment left to be sent by kopete: " << fragment
;
560 *msg
= i18n("Encryption error");
561 } else if ( fragment
){
562 *msg
= QString::fromUtf8( fragment
);
563 otrl_message_free( newMessage
);
564 otrl_message_free( fragment
);
568 OtrlMessageType type
= otrl_proto_message_type( msg
->toLocal8Bit() );
569 if( type
== OTRL_MSGTYPE_NOTOTR
| type
== OTRL_MSGTYPE_TAGGEDPLAINTEXT
){
570 msg
->replace( QString("<"), QString("<") );
577 KDE_EXPORT QString
OtrlChatInterface::getDefaultQuery( const QString
&accountId
){
579 message
= otrl_proto_default_query_msg( accountId
.toLatin1(), OTRL_POLICY_ALLOW_V2
);
580 QString
msg( message
);
581 otrl_message_free( message
);
585 KDE_EXPORT
void OtrlChatInterface::disconnectSession( Kopete::ChatSession
*chatSession
){
586 otrl_message_disconnect( userstate
, &ui_ops
, chatSession
, chatSession
->account()->accountId().toLatin1(), chatSession
->account()->protocol()->displayName().toLatin1(), chatSession
->members().first()->contactId().toLocal8Bit() );
587 OtrlChatInterface::self()->emitGoneSecure( chatSession
, 0 );
589 Kopete::Message
msg( chatSession
->account()->myself(), chatSession
->members().first() );
590 msg
.setPlainBody( i18n("Terminating OTR session.") );
591 msg
.setDirection( Kopete::Message::Internal
);
592 // msg.setBody( QString( message ), Kopete::Message::RichText );
593 chatSession
->appendMessage( msg
);
597 KDE_EXPORT
bool OtrlChatInterface::shouldDiscard( const QString
&message
){
598 if( !message
.isEmpty() && !message
.isNull() ){
599 // kDebug(14318) << otrl_proto_message_type( message.toLatin1() );
600 switch( otrl_proto_message_type( message
.toLatin1() ) ){
601 case OTRL_MSGTYPE_TAGGEDPLAINTEXT
:
602 case OTRL_MSGTYPE_UNKNOWN
: // Fragmented messages seem to be type UNKNOWN
603 case OTRL_MSGTYPE_NOTOTR
:
614 KDE_EXPORT
void OtrlChatInterface::setPolicy( OtrlPolicy policy
){
619 KDE_EXPORT
int OtrlChatInterface::privState( Kopete::ChatSession
*session
){
620 ConnContext
*context
;
622 context
= otrl_context_find(userstate
, session
->members().first()->contactId().toLocal8Bit(), session
->account()->accountId().toLocal8Bit(), session
->account()->protocol()->displayName().toLocal8Bit(), 0, NULL
, NULL
, NULL
);
625 switch( context
->msgstate
){
626 case OTRL_MSGSTATE_PLAINTEXT
:
628 case OTRL_MSGSTATE_ENCRYPTED
:
629 if( context
->active_fingerprint
->trust
&& context
->active_fingerprint
->trust
[0] != '\0' )
633 case OTRL_MSGSTATE_FINISHED
:
640 KDE_EXPORT QString
OtrlChatInterface::formatContact(const QString
&contactId
){
642 Kopete::MetaContact
*metaContact
= Kopete::ContactList::self()->findMetaContactByContactId(contactId
);
644 QString displayName
= metaContact
->displayName();
645 if((displayName
!= contactId
) && !displayName
.isNull()){
646 return displayName
+ " (" + contactId
+ ')';
652 KDE_EXPORT
void OtrlChatInterface::verifyFingerprint( Kopete::ChatSession
*session
){
653 ConnContext
*context
;
655 context
= otrl_context_find( userstate
, session
->members().first()->contactId().toLocal8Bit(), session
->account()->accountId().toLocal8Bit(), session
->protocol()->displayName().toLocal8Bit(), 0, NULL
, NULL
, NULL
);
657 new AuthenticationWizard( session
->view()->mainWidget(), context
, session
, true );
660 Fingerprint
*OtrlChatInterface::findFingerprint( Kopete::ChatSession
*session
){
661 ConnContext
*context
;
663 for( context
= userstate
->context_root
; context
!= NULL
; context
= context
->next
){
664 if( ( session
->members().first()->contactId().toLocal8Bit() == context
->username
) &&
665 (session
->account()->accountId().toLocal8Bit() == context
->accountname
) ){
666 return context
->active_fingerprint
? context
->active_fingerprint
: NULL
;
672 QString
OtrlChatInterface::findActiveFingerprint( Kopete::ChatSession
*session
){
673 ConnContext
*context
;
676 for( context
= userstate
->context_root
; context
!= NULL
; context
= context
->next
){
677 if( ( session
->members().first()->contactId().toLocal8Bit() == context
->username
) &&
678 (session
->account()->accountId().toLocal8Bit() == context
->accountname
) ){
679 otrl_privkey_hash_to_human( hash
, context
->active_fingerprint
->fingerprint
);
686 bool OtrlChatInterface::isVerified( Kopete::ChatSession
*session
){
687 Fingerprint
*fingerprint
= findFingerprint( session
);
689 kDebug() << "fingerprint" << fingerprint
;
690 if( fingerprint
->trust
&& fingerprint
->trust
[0] != '\0' ){
697 KDE_EXPORT
void OtrlChatInterface::checkFilePermissions( const QString
&file
){
698 if( QFile::exists( file
) ){
699 QFile
privkeys( file
);
700 QFileInfo
privkeysInfo( privkeys
);
701 if( !privkeysInfo
.permission( QFile::ReadOwner
| QFile::WriteOwner
) |
702 privkeysInfo
.permission( QFile::ReadGroup
) |
703 privkeysInfo
.permission( QFile::WriteGroup
) |
704 privkeysInfo
.permission( QFile::ExeGroup
) |
705 privkeysInfo
.permission( QFile::ReadOther
) |
706 privkeysInfo
.permission( QFile::WriteOther
) |
707 privkeysInfo
.permission( QFile::ExeOther
) ){
708 chmod( file
.toLocal8Bit(), 0600);
714 void OtrlChatInterface::emitGoneSecure( Kopete::ChatSession
*session
, int state
){
715 emit
goneSecure( session
, state
);
718 void OtrlChatInterface::setTrust( Kopete::ChatSession
*session
, bool trust
){
719 Fingerprint
*fingerprint
;
721 fingerprint
= findFingerprint( session
);
722 if( fingerprint
!= 0 ){
724 otrl_context_set_trust( fingerprint
, "verified" );
726 otrl_context_set_trust( fingerprint
, NULL
);
728 kDebug(14318) << "Writing fingerprints";
729 otrl_privkey_write_fingerprints( userstate
, QString( QString(KGlobal::dirs()->saveLocation("data", "kopete_otr/", true )) + "fingerprints" ).toLocal8Bit() );
730 emitGoneSecure( session
, privState( session
) );
732 kDebug(14318) << "could not find fingerprint";
736 /****************** SMP implementations ****************/
738 void OtrlChatInterface::abortSMP( ConnContext
*context
, Kopete::ChatSession
*session
){
739 otrl_message_abort_smp( userstate
, &ui_ops
, session
, context
);
740 if (context
->active_fingerprint
->trust
&& !context
->active_fingerprint
->trust
[0]) {
741 emitGoneSecure( session
, 1 );
743 Kopete::Message
msg( session
->members().first(), session
->account()->myself() );
744 msg
.setHtmlBody( i18n("<b>Authentication aborted. Note that the conversation is now insecure.</b>") );
745 msg
.setDirection( Kopete::Message::Internal
);
746 session
->appendMessage( msg
);
750 void OtrlChatInterface::initSMP( ConnContext
*context
, Kopete::ChatSession
*session
, const QString
&secret
){
751 context
= otrl_context_find( userstate
, session
->members().first()->contactId().toLocal8Bit(), session
->account()->accountId().toLocal8Bit(), session
->protocol()->displayName().toLocal8Bit(), 0, NULL
, NULL
, NULL
);
752 otrl_message_initiate_smp( userstate
, &ui_ops
, session
, context
, (unsigned char*)secret
.toLocal8Bit().data(), secret
.length() );
754 Kopete::Message
msg( session
->members().first(), session
->account()->myself() );
755 msg
.setHtmlBody( i18n("<b>Authenticating contact...</b>") );
756 msg
.setDirection( Kopete::Message::Internal
);
758 session
->appendMessage( msg
);
762 void OtrlChatInterface::initSMPQ( ConnContext
*context
, Kopete::ChatSession
*session
, const QString
&question
, const QString
&secret
){
763 context
= otrl_context_find( userstate
, session
->members().first()->contactId().toLocal8Bit(), session
->account()->accountId().toLocal8Bit(), session
->protocol()->displayName().toLocal8Bit(), 0, NULL
, NULL
, NULL
);
764 otrl_message_initiate_smp_q( userstate
, &ui_ops
, session
, context
, (const char*)question
.toLocal8Bit().data(), (unsigned char*)secret
.toLocal8Bit().data(), secret
.length() );
766 Kopete::Message
msg( session
->members().first(), session
->account()->myself() );
767 msg
.setHtmlBody( i18n("<b>Authenticating contact...</b>") );
768 msg
.setDirection( Kopete::Message::Internal
);
770 session
->appendMessage( msg
);
773 void OtrlChatInterface::respondSMP( ConnContext
*context
, Kopete::ChatSession
*session
, const QString
&secret
){
775 kDebug(14318) << "resonding SMP";
777 otrl_message_respond_smp( userstate
, &ui_ops
, session
, context
, (unsigned char*)secret
.toLocal8Bit().data(), secret
.length());
779 Kopete::Message
msg( session
->members().first(), session
->account()->myself() );
780 msg
.setHtmlBody( i18n("<b>Authenticating contact...</b>") );
781 msg
.setDirection( Kopete::Message::Internal
);
783 session
->appendMessage( msg
);
786 /****************** KeyGenThread *******************/
788 KeyGenThread::KeyGenThread( const QString
&accountname
, const QString
&protocol
){
789 this->accountname
= accountname
;
790 this->protocol
= protocol
;
794 void KeyGenThread::run()
796 QString storeFile
= QString(KGlobal::dirs()->saveLocation("data", "kopete_otr/", true )) + "privkeys";
797 otrl_privkey_generate(OtrlChatInterface::self()->getUserstate(), storeFile
.toLocal8Bit(), accountname
.toLocal8Bit(), protocol
.toLocal8Bit());
798 OtrlChatInterface::self()->checkFilePermissions( QString(KGlobal::dirs()->saveLocation("data", "kopete_otr/", true )) + "privkeys" );