Proof-reading.
[kdenetwork.git] / kopete / plugins / otr / otrlchatinterface.cpp
blobd77273b01368e973dc1280d9d5248e77f415a95c
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 /**
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>
38 #include <kdebug.h>
39 #include <kmessagebox.h>
40 #include <kstandarddirs.h>
41 #include <klocale.h>
42 #include <kpassivepopup.h>
43 #include <kpushbutton.h>
45 #include <Qt>
46 #include <qlabel.h>
47 #include <qnamespace.h>
48 #include <qeventloop.h>
49 #include <qapplication.h>
50 #include <qfile.h>
51 #include <qfileinfo.h>
52 #include <qwidget.h>
54 extern "C"{
55 #include <sys/types.h>
56 #include <sys/stat.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){
68 Q_UNUSED(context)
70 Kopete::ChatSession *session= ((Kopete::ChatSession*)opdata);
71 bool noerr;
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;
78 QString policy;
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 ) ){
82 case 1:
83 return OTRL_POLICY_ALWAYS;
84 case 2:
85 return OTRL_POLICY_OPPORTUNISTIC;
86 case 3:
87 return OTRL_POLICY_MANUAL;
88 case 4:
89 return OTRL_POLICY_NEVER;
90 default:
91 return confPolicy;
95 static void create_privkey(void *opdata, const char *accountname, const char *protocol){
96 Kopete::ChatSession *session= ((Kopete::ChatSession*)opdata);
98 if( !session->view() ){
99 session->raiseView();
101 PrivKeyPopup *popup = new PrivKeyPopup( session->view()->mainWidget() );
102 popup->show();
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 );
112 popup->close();
115 static int is_logged_in(void *opdata, const char *accountname, const char *protocol, const char *recipient){
117 Q_UNUSED(accountname)
118 Q_UNUSED(protocol)
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){
126 return -1;
127 } else if( status == Kopete::OnlineStatus::Offline ){
128 return 0;
129 } else {
130 return 1;
134 return -1;
137 static void inject_message( void *opdata, const char *accountname, const char *protocol, const char *recipient, const char *message ){
139 Q_UNUSED(accountname)
140 Q_UNUSED(protocol)
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 );
152 return;
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){
159 Q_UNUSED(opdata)
160 Q_UNUSED(level)
161 Q_UNUSED(accountname)
162 Q_UNUSED(protocol)
163 Q_UNUSED(username)
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)
171 Q_UNUSED(protocol)
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 );
181 return 0;
184 return 1;
187 static void update_context_list(void *opdata){
188 //Not used...
189 Q_UNUSED(opdata)
192 static const char *protocol_name(void *opdata, const char *protocol){
193 //Never seen...
195 Q_UNUSED(opdata)
196 Q_UNUSED(protocol)
198 // kdDebug() << "protocol_name called" << endl;
199 return 0;
202 static void protocol_name_free(void *opdata, const char *protocol_name){
203 //Never seen...
205 Q_UNUSED(opdata)
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]){
213 Q_UNUSED(us)
214 Q_UNUSED(accountname)
215 Q_UNUSED(protocol)
216 Q_UNUSED(username)
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){
229 Q_UNUSED(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);
246 } else {
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){
257 Q_UNUSED(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){
270 Q_UNUSED(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);
281 } else {
282 OtrlChatInterface::self()->emitGoneSecure( session, 1);
286 static void log_message(void *opdata, const char *message){
288 Q_UNUSED(opdata)
290 kDebug(14318) << "libotr: "<< message;
293 static int max_message_size(void *opdata, ConnContext *context){
294 Kopete::ChatSession *session= ((Kopete::ChatSession*)opdata);
296 Q_UNUSED(context)
298 kDebug(14318) << session->protocol()->pluginId();
300 if( session->protocol()->pluginId() == "MSNProtocol" ){
301 return 1409;
302 } else if( session->protocol()->pluginId() == "ICQProtocol" ){
303 return 1274;
304 } else if( session->protocol()->pluginId() == "AIMProtocol" ){
305 return 1274;
306 } else if( session->protocol()->pluginId() == "YahooProtocol" ){
307 return 700;
310 // Jabber doesn't need fragmentation. Return 0 to disable.
311 // GaduGadu seems to not need fragmentation too.
312 return 0;
315 static OtrlMessageAppOps ui_ops = {
316 policy,
317 create_privkey,
318 is_logged_in,
319 inject_message,
320 notify,
321 display_otr_message,
322 update_context_list,
323 protocol_name,
324 protocol_name_free,
325 new_fingerprint,
326 write_fingerprints,
327 gone_secure,
328 gone_insecure,
329 still_secure,
330 log_message,
331 max_message_size,
332 0, //not used yet...
333 0 //not used yet...
336 /*********************** Gui_UI_Ops finished *************************/
339 /*********************** Constructor/Destructor **********************/
341 OtrlChatInterface::OtrlChatInterface(){
342 mSelf = this;
343 OTRL_INIT;
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(){
361 if( !mSelf ){
362 new OtrlChatInterface();
364 return mSelf;
367 KDE_EXPORT void OtrlChatInterface::setPlugin( Kopete::Plugin *plugin ){
368 chatPlugin = plugin;
371 /********************* Chat section ***************************/
373 OtrlUserState OtrlChatInterface::getUserstate(){
374 return userstate;
378 KDE_EXPORT int OtrlChatInterface::decryptMessage( QString *msg, const QString &accountId,
379 const QString &protocol, const QString &contactId , Kopete::ChatSession *chatSession){
381 int ignoremessage;
382 char *newMessage = NULL;
383 OtrlTLV *tlvs = NULL;
384 OtrlTLV *tlv = 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);
391 if( tlv ){
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);
400 if (context) {
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;
408 } else {
409 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1Q);
410 if (tlv) {
411 if (nextMsg != OTRL_SMP_EXPECT1){
412 kDebug(14318) << "Abording SMP: 1Q";
413 abortSMP( context, chatSession );
414 } else {
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);
421 if (tlv) {
422 if (nextMsg != OTRL_SMP_EXPECT1){
423 kDebug(14318) << "Abording SMP: 1";
424 abortSMP( context, chatSession );
425 } else {
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);
431 if (tlv) {
432 if (nextMsg != OTRL_SMP_EXPECT2){
433 kDebug(14318) << "Abording SMP: 2";
434 abortSMP( context, chatSession );
435 } else {
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);
442 if (tlv) {
443 if (nextMsg != OTRL_SMP_EXPECT3){
444 kDebug(14318) << "Abording SMP: 3";
445 abortSMP( context, chatSession );
446 } else {
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 );
457 } else {
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 );
467 } else {
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);
480 if (tlv) {
481 if (nextMsg != OTRL_SMP_EXPECT4) {
482 kDebug(14318) << "Abording SMP: 4";
483 abortSMP( context, chatSession );
484 } else {
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 );
494 } else {
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);
507 if (tlv) {
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;
515 otrl_tlv_free(tlvs);
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
527 } else {
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 ){
536 int err;
537 char *newMessage;
538 char *fragment;
540 if( otrl_proto_message_type( msg->toLocal8Bit() ) == OTRL_MSGTYPE_NOTOTR ){
541 msg->replace( QString('<'), QString("&lt;") );
542 err = otrl_message_sending( userstate, &ui_ops, chatSession, accountId.toLocal8Bit(), protocol.toLocal8Bit(), contactId.toLocal8Bit(), msg->toUtf8(), NULL, &newMessage, NULL, NULL );
544 if( err != 0 ){
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;
559 if( err != 0){
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("&lt;"), QString("<") );
574 return msg;
577 KDE_EXPORT QString OtrlChatInterface::getDefaultQuery( const QString &accountId ){
578 char *message;
579 message = otrl_proto_default_query_msg( accountId.toLatin1(), OTRL_POLICY_ALLOW_V2 );
580 QString msg( message );
581 otrl_message_free( message );
582 return msg;
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:
604 return false;
605 default:
606 return true;
608 } else {
609 return false;
614 KDE_EXPORT void OtrlChatInterface::setPolicy( OtrlPolicy policy ){
615 confPolicy = 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);
624 if( context ){
625 switch( context->msgstate ){
626 case OTRL_MSGSTATE_PLAINTEXT:
627 return 0;
628 case OTRL_MSGSTATE_ENCRYPTED:
629 if( context->active_fingerprint->trust && context->active_fingerprint->trust[0] != '\0' )
630 return 2;
631 else
632 return 1;
633 case OTRL_MSGSTATE_FINISHED:
634 return 3;
637 return 0;
640 KDE_EXPORT QString OtrlChatInterface::formatContact(const QString &contactId){
642 Kopete::MetaContact *metaContact = Kopete::ContactList::self()->findMetaContactByContactId(contactId);
643 if( metaContact ){
644 QString displayName = metaContact->displayName();
645 if((displayName != contactId) && !displayName.isNull()){
646 return displayName + " (" + contactId + ')';
649 return 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;
669 return NULL;
672 QString OtrlChatInterface::findActiveFingerprint( Kopete::ChatSession *session ){
673 ConnContext *context;
674 char hash[45];
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 );
680 return hash;
683 return NULL;
686 bool OtrlChatInterface::isVerified( Kopete::ChatSession *session ){
687 Fingerprint *fingerprint = findFingerprint( session );
689 kDebug() << "fingerprint" << fingerprint;
690 if( fingerprint->trust && fingerprint->trust[0] != '\0' ){
691 return true;
692 } else {
693 return false;
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 ){
723 if( trust ){
724 otrl_context_set_trust( fingerprint, "verified" );
725 } else {
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 ) );
731 } else {
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" );