2 # define C_FUNCTION extern "C"
3 # define PROTO_NAME "psyc"
7 ///////////////////////////////////////////////////////////////////////////////
10 static char *strToC (const QString
&s
) {
11 //QTextCodec *tc = QTextCodec::codecForCStrings();
12 QTextCodec
*tc
= QTextCodec::codecForLocale();
14 if (tc
) ba
= tc
->fromUnicode(s
); else ba
= s
.toLatin1();
15 char *res
= (char *)malloc(ba
.size()+8);
16 strcpy(res
, ba
.constData());
17 res
[ba
.size()] = '\0';
23 static FILE *qxfopen (char *fname
, bool readOnly
) {
26 if (!mQF
.open(readOnly
? QIODevice::ReadOnly
: QIODevice::ReadWrite
)) return 0;
27 int hh
= dup(mQF
.handle());
29 FILE *res
= fdopen(hh
, readOnly
? "rb" : "r+b");
36 char *ChatForm::getOTRKeyFile (void) {
38 QString
otp(settingsDBPath(mAccName
));
41 otp
.append("keys.otr");
46 char *ChatForm::getOTRFingerFile (void) {
48 QString
otp(settingsDBPath(mAccName
));
51 otp
.append("fingers.otr");
56 char *ChatForm::getOTRInsTagFile (void) {
58 QString
otp(settingsDBPath(mAccName
));
61 otp
.append("instags.otr");
66 /* Return a pointer to a newly-allocated OTR query message, customized
67 * with our name. The caller should free() the result when he's done
69 static char *otrDefaultQueryMsg (const char *ourname
, OtrlPolicy policy
) {
70 char *msg
= otrl_proto_default_query_msg(ourname
, policy
);
71 char *e
= strchr(msg
, '\n');
73 char *res
= (char *)malloc(8192); //???
76 "%s\n%s has requested an Off-the-Record private conversation.\n"
77 "However, you do not have a plugin to support that.\n"
78 "See http://otr.cypherpunks.ca/ for more information.",
82 dlogf("otrDefaultQueryMsg:\n%s\n====", res
);
87 ///////////////////////////////////////////////////////////////////////////////
88 #define GET_FORM ChatForm *mForm = static_cast<ChatForm *>(opdata)
91 // return the OTR policy for the given context
92 C_FUNCTION OtrlPolicy
otrPolicyCB (void *opdata
, ConnContext
*context
) {
95 //!dlogf("otrPolicyCB()\n");
96 return OTRL_POLICY_DEFAULT
;
100 ///////////////////////////////////////////////////////////////////////////////
101 class GenKeyThread
: public QThread
{
107 //const char *protoName;
112 void GenKeyThread::run () {
115 FILE *fl = qxfopen(mForm->getOTRKeyFile(), false);
117 mError = otrl_privkey_generate_FILEp(mForm->mOTRState, fl, accName, protoName) != 0;
121 if (otrl_privkey_generate_calculate(keyp
)) {
122 dlogf("ERROR: can't generate new private key for '%s'!\n", accName
);
130 void ChatForm::genOTRKey (const char *accName
, const char *protoName
) {
132 if (otrl_privkey_generate_start(mOTRState
, accName
, protoName
, &keyp
)) {
133 dlogf("ERROR: can't generate new private key for '%s'!\n", accName
);
136 GenKeyWin
*gkw
= new GenKeyWin(accName
, this);
139 //!dlogf("dialog shown");
143 gtrd
.accName
= accName
;
144 //gtrd.protoName = protoName;
146 connect(>rd
, SIGNAL(finished()), &eloop
, SLOT(quit()));
148 //!dlogf("thread started");
151 //!dlogf("all done");
152 //TODO: check for error!
154 FILE *fl
= qxfopen(getOTRKeyFile(), false);
156 if (otrl_privkey_generate_finish_FILEp(mOTRState
, keyp
, fl
)) {
157 dlogf("ERROR: can't generate new private key for '%s'!\n", accName
);
166 // create a private key for the given accountname/protocol if desired
167 C_FUNCTION
void otrCreateKeyCB (void *opdata
, const char *accName
, const char *protoName
) {
172 dlogf("otrCreateKeyCB(): acc:[%s]; proto:[%s]\n", accName
, protoName
);
173 //!dlogf(" otrl_privkey_generate()...");
174 mForm
->genOTRKey(accName
, protoName
);
175 //otrl_privkey_generate(mOTRState, mForm->getOTRKeyFile(), accName, protoName);
180 ///////////////////////////////////////////////////////////////////////////////
181 /* Report whether you think the given user is online. Return 1 if
182 * you think he is, 0 if you think he isn't, -1 if you're not sure.
184 * If you return 1, messages such as heartbeats or other
185 * notifications may be sent to the user, which could result in "not
186 * logged in" errors if you're wrong. */
187 C_FUNCTION
int otrIsLoggedInCB (void *opdata
, const char *accName
, const char *protoName
, const char *recipient
) {
193 //!dlogf("otrIsLoggedInCB(): acc:[%s]; proto:[%s]; rcp:[%s]\n", accName, protoName, recipient);
194 if (!mForm
|| !recipient
|| !recipient
[0]) return 0;
195 PsycContact
*cc
= mForm
->findContact(recipient
);
196 if (!cc
|| cc
->isPlace()) return 0;
197 switch (cc
->status()) {
198 case PsycProto::Internal
:
199 case PsycProto::Offline
:
208 ///////////////////////////////////////////////////////////////////////////////
209 // send the given IM to the given recipient from the given accountname/protocol
210 C_FUNCTION
void otrSendMessageCB (void *opdata
, const char *accName
, const char *protoName
,
211 const char *recipient
, const char *message
)
219 dlogf("otrSendMessageCB(): acc:[%s]; proto:[%s]; rcp:[%s]\nmsg:[%s]\n=========", accName
, protoName
, recipient
, message
);
220 //!dlogf("otrSendMessageCB(): acc:[%s]; proto:[%s]; rcp:[%s]\n", accName, protoName, recipient);
221 if (!mForm
->proto()) return;
222 mForm
->proto()->sendMessage(QString(recipient
), QString::fromUtf8(message
), QString());
226 ///////////////////////////////////////////////////////////////////////////////
227 // When the list of ConnContexts changes (including a change in state), this is called so the UI can be updated
228 C_FUNCTION
void otrUpdateContextListCB (void *opdata
) {
230 ChatForm
*mForm
= static_cast<ChatForm
*>(opdata
);
231 //!dlogf("otrUpdateContextListCB()\n");
232 ConnContext
*context
= mForm
->mOTRState
->context_root
;
234 ConnContext
*next
= context
->next
;
235 PsycContact
*cc
= mForm
->findContact(context
->username
);
237 cc
->setOTRVerified(context
->active_fingerprint
&& context
->active_fingerprint
->trust
&&
238 (!strcmp(context
->active_fingerprint
->trust
, "verified") || !strcmp(context
->active_fingerprint
->trust
, "smp"))
240 if (cc
->isOTRActive() != (context
->msgstate
== OTRL_MSGSTATE_ENCRYPTED
)) {
241 cc
->setOTRActive(context
->msgstate
== OTRL_MSGSTATE_ENCRYPTED
);
242 mForm
->redrawContact(cc
);
250 ///////////////////////////////////////////////////////////////////////////////
251 /* Return a newly-allocated string containing a human-friendly name
252 * for the given protocol id */
254 C_FUNCTION const char *otrProtoNameCB (void *opdata, const char *protoName) {
257 //ChatForm *mForm = static_cast<ChatForm *>(opdata);
258 //!dlogf("otrProtoNameCB(): proto:[%s]\n", protoName);
264 /* Deallocate a string allocated by protocol_name */
266 C_FUNCTION void otrProtoNameFreeCB (void *opdata, const char *protoName) {
269 //ChatForm *mForm = static_cast<ChatForm *>(opdata);
270 //!dlogf("otrProtoNameFreeCB(): proto:[%s]\n", protoName);
275 ///////////////////////////////////////////////////////////////////////////////
276 /* A new fingerprint for the given user has been received. */
277 C_FUNCTION
void otrNewFingerCB (void *opdata
, OtrlUserState us
, const char *accName
, const char *protoName
,
278 const char *userName
, unsigned char fingerprint
[20])
285 Q_UNUSED(fingerprint
)
286 ChatForm
*mForm
= static_cast<ChatForm
*>(opdata
);
287 //!dlogf("otrNewFingerCB(): acc:[%s]; proto:[%s]; user:[%s]\n", accName, protoName, userName);
288 ConnContext
*context
= otrl_context_find(us
, userName
, accName
, protoName
, OTRL_INSTAG_BEST
, TRUE
, 0, NULL
/*add_appdata*/, NULL
/*opdata*/);
289 char hash
[OTRL_PRIVKEY_FPRINT_HUMAN_LEN
];
290 // don't add unknown fingerprint
291 Fingerprint
*fp
= otrl_context_find_fingerprint(context
, fingerprint
, 0/*FALSE*/, NULL
);
293 otrl_privkey_hash_to_human(hash
, fp
->fingerprint
);
294 dlogf(" known %strusted fingerprint: %s\n", (otrl_context_is_fingerprint_trusted(fp
) ? "" : "un"), hash
);
295 // trust it (user query?)
296 otrl_context_set_trust(fp
, "verified");
298 otrl_privkey_hash_to_human(hash
, fingerprint
);
299 dlogf(" new fingerprint: %s\n", hash
);
300 QMessageBox::StandardButton qres
=
301 QMessageBox::question(mForm
, "Dyskinesia: new OTR fingerprint",
302 QString("New OTR fingerpring received from %1.\n%2\nDo you trust it?").arg(userName
).arg(hash
),
303 QMessageBox::Yes
| QMessageBox::No
, QMessageBox::Yes
);
304 if (qres
== QMessageBox::Yes
) {
305 otrl_context_set_trust(fp
, "verified");
307 otrl_context_set_trust(fp
, "unknown");
313 ///////////////////////////////////////////////////////////////////////////////
314 /* The list of known fingerprints has changed. Write them to disk. */
315 C_FUNCTION
void otrWriteFingersCB (void *opdata
) {
317 //!dlogf("otrWriteFingersCB()\n");
318 FILE *fl
= qxfopen(mForm
->getOTRFingerFile(), false);
320 otrl_privkey_write_fingerprints_FILEp(mForm
->mOTRState
, fl
);
326 ///////////////////////////////////////////////////////////////////////////////
327 /* A ConnContext has entered a secure state. */
328 C_FUNCTION
void otrGoneSecureCB (void *opdata
, ConnContext
*context
) {
332 dlogf("otrGoneSecureCB()\n");
333 bool trusted
= (context
->active_fingerprint
&& context
->active_fingerprint
->trust
&&
334 (!strcmp(context
->active_fingerprint
->trust
, "verified") || !strcmp(context
->active_fingerprint
->trust
, "smp"))
336 PsycContact
*cc
= mForm
->findContact(context
->username
);
337 //!k8:if (cc) cc->setOTRActive(true);
339 dlogf(" Beginning OTR encrypted session with [%s]", context
->username
);
340 if (cc
) cc
->setOTRVerified(true);
341 // opdata is hContact
342 //SetEncryptionStatus((HANDLE)opdata, true);
344 //!!CloseHandle((HANDLE)_beginthreadex(0, 0, verify_fp_thread, context, 0, 0));
345 dlogf(" Beginning OTR encrypted session with [%s] (NOT VERIFIED)", context
->username
);
346 if (cc
) cc
->setOTRVerified(false);
347 // opdata is hContact
348 //SetEncryptionStatus((HANDLE)opdata, true);
350 //!k8:if (cc) mForm->redrawContact(cc);
354 ///////////////////////////////////////////////////////////////////////////////
355 // a ConnContext has left a secure state
356 C_FUNCTION
void otrGoneInsecureCB (void *opdata
, ConnContext
*context
) {
359 ChatForm
*mForm
= static_cast<ChatForm
*>(opdata
);
360 //dlogf("otrGoneInsecureCB()\n");
361 dlogf(" OTR encrypted session with [%s] has ended", context
->username
);
363 PsycContact *cc = mForm->findContact(context->username);
364 if (cc && cc->isOTRActive()) {
365 cc->setOTRActive(false);
366 mForm->redrawContact(cc);
369 mForm
->otrDisconnect(context
->username
);
370 // opdata is hContact
371 //SetEncryptionStatus((HANDLE)opdata, false);
375 ///////////////////////////////////////////////////////////////////////////////
376 /* We have completed an authentication, using the D-H keys we
377 * already knew. isReply indicates whether we initiated the AKE. */
378 C_FUNCTION
void otrStillSecureCB (void *opdata
, ConnContext
*context
, int isReply
) {
382 //ChatForm *mForm = static_cast<ChatForm *>(opdata);
384 dlogf("otrStillSecureCB()\n");
386 dlogf(" OTR encrypted session with [%s] is being continued", context->username);
390 PsycContact *cc = mForm->findContact(context->username);
391 if (cc && !cc->isOTRActive()) {
392 cc->setOTRActive(true);
393 mForm->redrawContact(cc);
396 // opdata is hContact
397 //SetEncryptionStatus((HANDLE)opdata, true);
401 ///////////////////////////////////////////////////////////////////////////////
402 C_FUNCTION
int otrMaxMessageSizeCB (void *opdata
, ConnContext
*context
) {
403 //ChatForm *mForm = static_cast<ChatForm *>(opdata);
406 //dlogf("max_message_size()\n");
412 ///////////////////////////////////////////////////////////////////////////////
413 C_FUNCTION const char *otrAccountNameCB (void *opdata, const char *accName, const char *protoName) {
414 ChatForm *mForm = static_cast<ChatForm *>(opdata);
415 dlogf("account_name(): acc:[%s]; proto:[%s]\n", accName, protoName);
419 ///////////////////////////////////////////////////////////////////////////////
420 C_FUNCTION void otrAccountNameFreeCB(void *opdata, const char *accName) {
421 ChatForm *mForm = static_cast<ChatForm *>(opdata);
422 dlogf("account_name_free(): acc:[%s]\n", accName);
427 ///////////////////////////////////////////////////////////////////////////////
428 C_FUNCTION
const char *otrErrorMessageCB (void *opdata
, ConnContext
*context
, OtrlErrorCode err_code
) {
433 case OTRL_ERRCODE_ENCRYPTION_ERROR
: return "ENCRYPTION_ERROR";
434 case OTRL_ERRCODE_MSG_NOT_IN_PRIVATE
: return "MSG_NOT_IN_PRIVATE";
435 case OTRL_ERRCODE_MSG_UNREADABLE
: return "MSG_UNREADABLE";
436 case OTRL_ERRCODE_MSG_MALFORMED
: return "MSG_MALFORMED";
437 default: return "UNKNOWN";
442 C_FUNCTION
void otrErrorMessageFreeCB (void *opdata
, const char *err_msg
) {
448 ///////////////////////////////////////////////////////////////////////////////
449 C_FUNCTION
void otrHandleSMPEvent (void *opdata
, OtrlSMPEvent smp_event
,
450 ConnContext
*context
, unsigned short progress_percent
, char *question
);
453 C_FUNCTION
void otrTimerControlCB (void *opdata
, unsigned int interval
) {
454 dlogf("otrTimerControlCB: interval=%u", interval
);
455 ChatForm
*frm
= (ChatForm
*)opdata
;
456 frm
->restartOTRTimer(interval
);
460 ///////////////////////////////////////////////////////////////////////////////
461 C_FUNCTION
void otrHandleMsgEvent (void *opdata
, OtrlMessageEvent msg_event
, ConnContext
*context
,
462 const char *message
, gcry_error_t err
)
470 case OTRL_MSGEVENT_NONE
:
471 dlogf("OTRL_MSGEVENT_NONE\nNo event");
473 case OTRL_MSGEVENT_ENCRYPTION_REQUIRED
:
474 dlogf("OTRL_MSGEVENT_ENCRYPTION_REQUIRED\nOur policy requires encryption but we are trying to send an unencrypted message out.");
476 case OTRL_MSGEVENT_ENCRYPTION_ERROR
:
477 dlogf("OTRL_MSGEVENT_ENCRYPTION_ERROR\nAn error occured while encrypting a message and the message was not sent.");
479 case OTRL_MSGEVENT_CONNECTION_ENDED
:
480 dlogf("OTRL_MSGEVENT_CONNECTION_ENDED\nMessage has not been sent because our buddy has ended the private conversation. We should either close the connection, or refresh it.");
482 case OTRL_MSGEVENT_SETUP_ERROR
:
483 dlogf("OTRL_MSGEVENT_SETUP_ERROR\nA private conversation could not be set up. A gcry_error_t will be passed.");
485 case OTRL_MSGEVENT_MSG_REFLECTED
:
486 dlogf("OTRL_MSGEVENT_MSG_REFLECTED\nReceived our own OTR messages.");
488 case OTRL_MSGEVENT_MSG_RESENT
:
489 dlogf("OTRL_MSGEVENT_MSG_RESENT\nThe previous message was resent.");
491 case OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE
:
492 dlogf("OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE\nReceived an encrypted message but cannot read it because no private connection is established yet.");
494 case OTRL_MSGEVENT_RCVDMSG_UNREADABLE
:
495 dlogf("OTRL_MSGEVENT_RCVDMSG_UNREADABLE\nCannot read the received message.");
497 case OTRL_MSGEVENT_RCVDMSG_MALFORMED
:
498 dlogf("OTRL_MSGEVENT_RCVDMSG_MALFORMED\nThe message received contains malformed data.");
500 case OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD
:
501 dlogf("OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD\nReceived a heartbeat.");
503 case OTRL_MSGEVENT_LOG_HEARTBEAT_SENT
:
504 dlogf("OTRL_MSGEVENT_LOG_HEARTBEAT_SENT\nSent a heartbeat.");
506 case OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR
:
507 dlogf("OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR\nReceived a general OTR error. The argument 'message' will also be passed and it will contain the OTR error message."
508 "\nmessage=%s\n====", message
);
510 case OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED
:
511 dlogf("OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED\nReceived an unencrypted message. The argument 'message' will also be passed and it will contain the plaintext message."
512 "\nmessage=%s\n====", message
);
514 case OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED
:
515 dlogf("OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED\nCannot recognize the type of OTR message received.");
517 case OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE
:
518 dlogf("OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE\nReceived and discarded a message intended for another instance.");
524 ////////////////////////////////////////////////////////////////////////////////
525 C_FUNCTION
void otrCreateInsTagCB (void *opdata
, const char *accountname
, const char *protocol
) {
526 dlogf("otrCreateInsTagCB: acc=[%s]; proto=[%s]\n", accountname
, protocol
);
528 FILE *fl
= qxfopen(mForm
->getOTRInsTagFile(), false);
530 if (otrl_instag_generate_FILEp(mForm
->mOTRState
, fl
, accountname
, protocol
)) {
531 dlogf("ERROR: can't generate new private key for '%s'!\n", accountname
);
538 ///////////////////////////////////////////////////////////////////////////////
539 static OtrlMessageAppOps ops
= {
540 otrPolicyCB
, /* Return the OTR policy for the given context. */
541 otrCreateKeyCB
, /* Create a private key for the given accountname/protocol if desired. */
542 /* Report whether you think the given user is online. Return 1 if
543 * you think he is, 0 if you think he isn't, -1 if you're not sure.
545 * If you return 1, messages such as heartbeats or other
546 * notifications may be sent to the user, which could result in "not
547 * logged in" errors if you're wrong. */
549 /* Send the given IM to the given recipient from the given
550 * accountname/protocol. */
552 /* When the list of ConnContexts changes (including a change in
553 * state), this is called so the UI can be updated. */
554 otrUpdateContextListCB
, // can be NULL
555 /* A new fingerprint for the given user has been received. */
557 /* The list of known fingerprints has changed. Write them to disk. */
559 /* A ConnContext has entered a secure state. */
561 /* A ConnContext has left a secure state. */
563 /* We have completed an authentication, using the D-H keys we
564 * already knew. is_reply indicates whether we initiated the AKE. */
566 /* Find the maximum message size supported by this protocol. */
568 /* Return a newly allocated string containing a human-friendly
569 * representation for the given account */
570 NULL
, /* account_name */
571 /* Deallocate a string returned by account_name */
572 NULL
, /* account_name_free */
573 /* We received a request from the buddy to use the current "extra"
574 * symmetric key. The key will be passed in symkey, of length
575 * OTRL_EXTRAKEY_BYTES. The requested use, as well as use-specific
576 * data will be passed so that the applications can communicate other
577 * information (some id for the data transfer, for example). */
579 /* Return a string according to the error event. This string will then
580 * be concatenated to an OTR header to produce an OTR protocol error
581 * message. The following are the possible error events:
582 * - OTRL_ERRCODE_ENCRYPTION_ERROR
583 * occured while encrypting a message
584 * - OTRL_ERRCODE_MSG_NOT_IN_PRIVATE
585 * sent encrypted message to somebody who is not in a mutual OTR session
586 * - OTRL_ERRCODE_MSG_UNREADABLE
587 * sent an unreadable encrypted message
588 * - OTRL_ERRCODE_MSG_MALFORMED
589 * message sent is malformed */
591 /* Deallocate a string returned by otr_error_message */
592 otrErrorMessageFreeCB
, // can be NULL
593 /* Return a string that will be prefixed to any resent message. If this
594 * function is not provided by the application then the default prefix,
595 * "[resent]", will be used.
597 //const char *(*resent_msg_prefix)(void *opdata, ConnContext *context);
599 /* Deallocate a string returned by resent_msg_prefix */
600 //void (*resent_msg_prefix_free)(void *opdata, const char *prefix);
602 /* Update the authentication UI with respect to SMP events
603 * These are the possible events:
604 * - OTRL_SMPEVENT_ASK_FOR_SECRET
605 * prompt the user to enter a shared secret. The sender application
606 * should call otrl_message_initiate_smp, passing NULL as the question.
607 * When the receiver application resumes the SM protocol by calling
608 * otrl_message_respond_smp with the secret answer.
609 * - OTRL_SMPEVENT_ASK_FOR_ANSWER
610 * (same as OTRL_SMPEVENT_ASK_FOR_SECRET but sender calls
611 * otrl_message_initiate_smp_q instead)
612 * - OTRL_SMPEVENT_CHEATED
613 * abort the current auth and update the auth progress dialog
614 * with progress_percent. otrl_message_abort_smp should be called to
615 * stop the SM protocol.
616 * - OTRL_SMPEVENT_INPROGRESS and
617 * OTRL_SMPEVENT_SUCCESS and
618 * OTRL_SMPEVENT_FAILURE and
619 * OTRL_SMPEVENT_ABORT
620 * update the auth progress dialog with progress_percent
621 * - OTRL_SMPEVENT_ERROR
622 * (same as OTRL_SMPEVENT_CHEATED)
625 /* Handle and send the appropriate message(s) to the sender/recipient
626 * depending on the message events. All the events only require an opdata,
627 * the event, and the context. The message and err will be NULL except for
628 * some events (see below). The possible events are:
629 * - OTRL_MSGEVENT_ENCRYPTION_REQUIRED
630 * Our policy requires encryption but we are trying to send
631 * an unencrypted message out.
632 * - OTRL_MSGEVENT_ENCRYPTION_ERROR
633 * An error occured while encrypting a message and the message
635 * - OTRL_MSGEVENT_CONNECTION_ENDED
636 * Message has not been sent because our buddy has ended the
637 * private conversation. We should either close the connection,
639 * - OTRL_MSGEVENT_SETUP_ERROR
640 * A private conversation could not be set up. A gcry_error_t
642 * - OTRL_MSGEVENT_MSG_REFLECTED
643 * Received our own OTR messages.
644 * - OTRL_MSGEVENT_MSG_RESENT
645 * The previous message was resent.
646 * - OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE
647 * Received an encrypted message but cannot read
648 * it because no private connection is established yet.
649 * - OTRL_MSGEVENT_RCVDMSG_UNREADABLE
650 * Cannot read the received message.
651 * - OTRL_MSGEVENT_RCVDMSG_MALFORMED
652 * The message received contains malformed data.
653 * - OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD
654 * Received a heartbeat.
655 * - OTRL_MSGEVENT_LOG_HEARTBEAT_SENT
657 * - OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR
658 * Received a general OTR error. The argument 'message' will
659 * also be passed and it will contain the OTR error message.
660 * - OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED
661 * Received an unencrypted message. The argument 'message' will
662 * also be passed and it will contain the plaintext message.
663 * - OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED
664 * Cannot recognize the type of OTR message received.
665 * - OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE
666 * Received and discarded a message intended for another instance. */
668 /* Create a instance tag for the given accountname/protocol if
671 /* Called immediately before a data message is encrypted, and after a data
672 * message is decrypted. The OtrlConvertType parameter has the value
673 * OTRL_CONVERT_SENDING or OTRL_CONVERT_RECEIVING to differentiate these
675 //void (*convert_msg)(void *opdata, ConnContext *context, OtrlConvertType convert_type, char ** dest, const char *src);
677 /* Deallocate a string returned by convert_msg. */
678 //void (*convert_free)(void *opdata, ConnContext *context, char *dest);
680 /* When timer_control is called, turn off any existing periodic
683 * Additionally, if interval > 0, set a new periodic timer
684 * to go off every interval seconds. When that timer fires, you
685 * must call otrl_message_poll(userstate, uiops, uiopdata); from the
686 * main libotr thread.
688 * The timing does not have to be exact; this timer is used to
689 * provide forward secrecy by cleaning up stale private state that
690 * may otherwise stick around in memory. Note that the
691 * timer_control callback may be invoked from otrl_message_poll
692 * itself, possibly to indicate that interval == 0 (that is, that
693 * there's no more periodic work to be done at this time).
695 * If you set this callback to NULL, then you must ensure that your
696 * application calls otrl_message_poll(userstate, uiops, uiopdata);
697 * from the main libotr thread every definterval seconds (where
698 * definterval can be obtained by calling
699 * definterval = otrl_message_poll_get_default_interval(userstate);
700 * right after creating the userstate). The advantage of
701 * implementing the timer_control callback is that the timer can be
702 * turned on by libotr only when it's needed.
704 * It is not a problem (except for a minor performance hit) to call
705 * otrl_message_poll more often than requested, whether
706 * timer_control is implemented or not.
708 * If you fail to implement the timer_control callback, and also
709 * fail to periodically call otrl_message_poll, then you open your
710 * users to a possible forward secrecy violation: an attacker that
711 * compromises the user's computer may be able to decrypt a handful
712 * of long-past messages (the first messages of an OTR
719 ///////////////////////////////////////////////////////////////////////////////
720 C_FUNCTION
void otrHandleSMPEvent (void *opdata
, OtrlSMPEvent smp_event
,
721 ConnContext
*context
, unsigned short progress_percent
, char *question
)
724 Q_UNUSED(progress_percent
)
725 ChatForm
*frm
= (ChatForm
*)opdata
;
726 dlogf("otrHandleSMPEvent: event=%u; user=[%s]; account=[%s]; proto=[%s]", (unsigned)smp_event
, context
->username
, context
->accountname
, context
->protocol
);
727 if (smp_event
== OTRL_SMPEVENT_ASK_FOR_SECRET
) {
729 dlogf("otrHandleSMPEvent: ask_for_secret; user=[%s]; account=[%s]; proto=[%s]", context
->username
, context
->accountname
, context
->protocol
);
731 QString reply
= QInputDialog::getText(frm
, "OTR SMP query",
732 QString("OTR SMP query from %1:\nsecret question:").arg(context
->username
),
733 QLineEdit::Normal
, QString(), &ok
);
734 if (!ok
|| reply
.isEmpty()) {
735 otrl_message_abort_smp(frm
->mOTRState
, &ops
, opdata
, context
);
737 QByteArray
ba(reply
.toUtf8());
738 otrl_message_respond_smp(frm
->mOTRState
, &ops
, opdata
, context
, (const unsigned char *)ba
.constData(), ba
.size());
742 if (smp_event
== OTRL_SMPEVENT_ASK_FOR_ANSWER
) {
744 QString reply
= QInputDialog::getText(frm
, "OTR SMP query",
745 QString("OTR SMP query from %1:\nsecret question is: %2").arg(context
->username
).arg(question
),
746 QLineEdit::Normal
, QString(), &ok
);
747 if (!ok
|| reply
.isEmpty()) {
748 otrl_message_abort_smp(frm
->mOTRState
, &ops
, opdata
, context
);
750 QByteArray
ba(reply
.toUtf8());
751 otrl_message_respond_smp(frm
->mOTRState
, &ops
, opdata
, context
, (const unsigned char *)ba
.constData(), ba
.size());
755 if (smp_event
== OTRL_SMPEVENT_CHEATED
/*|| smp_event == OTRL_SMPEVENT_ERROR*/) {
756 dlogf(" ** protocol violated, aborting");
757 otrl_message_abort_smp(frm
->mOTRState
, &ops
, opdata
, context
);
758 otrl_sm_state_free(context
->smstate
);
761 if (smp_event
== OTRL_SMPEVENT_SUCCESS
) {
762 if (context
->smstate
->received_question
) {
763 dlogf(" ** correct answer, you are trusted");
765 dlogf(" ** secrets proved equal, fingerprint trusted");
767 otrl_sm_state_free(context
->smstate
);
770 if (smp_event
== OTRL_SMPEVENT_FAILURE
) {
771 if (context
->smstate
->received_question
) {
772 dlogf(" ** wrong answer, you are not trusted");
774 dlogf(" ** secrets did not match, fingerprint not trusted");
776 otrl_sm_state_free(context
->smstate
);
779 if (smp_event
== OTRL_SMPEVENT_FAILURE
) {
780 dlogf(" ** received abort");
781 otrl_sm_state_free(context
->smstate
);
784 if (smp_event
== OTRL_SMPEVENT_ERROR
) {
785 dlogf(" ** protocol error, aborting");
786 otrl_message_abort_smp(frm
->mOTRState
, &ops
, opdata
, context
);
787 otrl_sm_state_free(context
->smstate
);
793 ///////////////////////////////////////////////////////////////////////////////
794 void ChatForm::otrSendMessage (const QString
&auni
, const QString
&txt
, const QString
&act
) {
795 QString
uni(auni
.toLower());
796 PsycContact
*cc
= findContact(uni
);
797 if (!cc
|| cc
->isPlace() || !cc
->isOTRActive() || txt
.startsWith("?OTR")) {
798 // internal OTR message or room message
799 mProto
->sendMessage(uni
, txt
, act
);
801 // not OTR message, encrypt it
804 //ConnContext *context;
805 QByteArray
me(mProto
->uni().toLower().toUtf8());
806 QByteArray
to(uni
.toUtf8());
807 QByteArray
msg(txt
.toUtf8());
808 err
= otrl_message_sending(mOTRState
, &ops
, (void *)this, me
, PROTO_NAME
, to
,
809 OTRL_INSTAG_BEST
, // instag
811 NULL
, // no additional TLVs
813 /*OTRL_FRAGMENT_SEND_SKIP*/OTRL_FRAGMENT_SEND_ALL
, // fragmentation policy
815 NULL
, // add_appdata callback
819 dlogf("failure to encrypt message!\n");
823 dlogf("WTF?! an empty OTR resulting message!\n");
824 //mProto->sendMessage(uni, txt, act);
827 //QByteArray mx(newMsg);
828 //mProto->sendMessage(uni, mx, act);
830 ConnContext *context = otrl_context_find(mOTRState, to, me, PROTO_NAME, OTRL_INSTAG_BEST, FALSE, 0, 0, 0);
833 err = otrl_message_fragment_and_send(&ops, (void *)this, context, newMsg, OTRL_FRAGMENT_SEND_ALL, &frag);
834 if (frag) free(frag);
836 dlogf("WTF?! no context found for otrl_message_fragment_and_send()\n");
839 otrl_message_free(newMsg
);
844 ///////////////////////////////////////////////////////////////////////////////
845 QString
ChatForm::otrGotMessage (const QString
&auni
, const QString
&txt
) {
850 QString
uni(auni
.toLower());
851 QByteArray
me(mProto
->uni().toLower().toUtf8());
852 QByteArray
sender(uni
.toUtf8());
853 QByteArray
msg(txt
.toUtf8());
855 ConnContext
*context
;
856 isInternal
= otrl_message_receiving(mOTRState
, &ops
, (void *)this, me
, PROTO_NAME
, sender
, msg
,
857 &newMsg
, &tlvs
, &context
, NULL
, NULL
);
858 //ConnContext *context = otrl_context_find(mOTRState, sender, me, PROTO_NAME, OTRL_INSTAG_BEST, FALSE, 0, 0, 0);
860 dlogf("otrGotMessage: user=[%s]; account=[%s]; proto=[%s]", context
->username
, context
->accountname
, context
->protocol
);
862 dlogf("otrGotMessage: NO CONTEXT!");
866 bool disconnected = false;
868 OtrlTLV *tlv = otrl_tlv_find(tlvs, OTRL_TLV_DISCONNECTED);
869 if (tlv) disconnected = true;
870 if (tlvs) otrl_tlv_free(tlvs);
875 dlogf("internal message\n");
877 dlogf("MSG:===\n%s\n===", newMsg
);
878 otrl_message_free(newMsg
);
880 dlogf("ORIGMSG:===\n%s\n===", msg
.constData());
884 dlogf("[%s] has terminated the OTR session\n", me.constData());
891 // it may not be encrypted however (e.g. tagged plaintext with tags stripped)
892 //!if (context && context->msgstate == OTRL_MSGSTATE_PLAINTEXT) dlogf("PLAIN TEXT!\n");
896 QByteArray
ba(txt
.toUtf8());
897 dlogf("plain message: [%s]\n", ba
.constData());
900 res
= QString::fromUtf8(newMsg
);
901 dlogf("decrypted message: [%s]\n", newMsg
);
904 if (newMsg
) otrl_message_free(newMsg
);
908 dlogf("[%s] has terminated the OTR session\n", me.constData());
915 ///////////////////////////////////////////////////////////////////////////////
919 const QString
ChatForm::otrGetFinger (const QString
&aUNI
) {
922 PsycContact
*cc
= findContact(aUNI
);
923 if (!cc
|| cc
->isPlace()) return QString();
924 QByteArray
me(mProto
->uni().toLower().toUtf8());
925 QByteArray
usr(aUNI
.toLower().toUtf8());
926 ConnContext
*context
= otrl_context_find(mOTRState
, usr
, me
, PROTO_NAME
, OTRL_INSTAG_BEST
, FALSE
, 0, NULL
, NULL
);
927 if (context
&& context
->active_fingerprint
) {
928 char hash
[OTRL_PRIVKEY_FPRINT_HUMAN_LEN
];
929 otrl_privkey_hash_to_human(hash
, context
->active_fingerprint
->fingerprint
);
930 return QString(hash
);
932 dlogf("no finger for [%s]", usr
.constData());
939 void ChatForm::otrSetTrust (const QString
&aUNI
, bool tflag
) {
943 PsycContact
*cc
= findContact(aUNI
);
944 if (!cc
|| cc
->isPlace()) return;
945 QByteArray
me(mProto
->uni().toLower().toUtf8());
946 QByteArray
usr(aUNI
.toLower().toUtf8());
947 ConnContext
*context
= otrl_context_find(mOTRState
, usr
, me
, PROTO_NAME
, OTRL_INSTAG_BEST
, FALSE
, 0, NULL
, NULL
);
948 if (context
&& context
->active_fingerprint
) {
949 otrl_context_set_trust(context
->active_fingerprint
, tflag
? "verified" : "unknown");
951 if (cc
->isOTRVerified() != tflag
) {
952 cc
->setOTRVerified(tflag
);
959 void ChatForm::otrForget (const QString
&aUNI
) {
962 PsycContact
*cc
= findContact(aUNI
);
963 if (!cc
|| cc
->isPlace()) return;
964 QByteArray
me(mProto
->uni().toLower().toUtf8());
965 QByteArray
usr(aUNI
.toLower().toUtf8());
966 ConnContext
*context
= otrl_context_find(mOTRState
, usr
, me
, PROTO_NAME
, OTRL_INSTAG_BEST
, FALSE
, 0, NULL
, NULL
);
968 otrl_context_forget(context
);
969 cc
->setOTRVerified(false);
976 void ChatForm::otrInitiateSMP (const QString
&aUNI
, const QString
&secret
, const QString
&question
) {
981 PsycContact
*cc
= findContact(aUNI
);
982 if (!cc
|| cc
->isPlace() || !cc
->isOTRActive()) return;
983 //cc->setOTRVerified(false);
985 QByteArray
me(mProto
->uni().toLower().toUtf8());
986 QByteArray
user(aUNI
.toLower().toUtf8());
987 ConnContext
*context
= otrl_context_find(mOTRState
, user
, me
, PROTO_NAME
, OTRL_INSTAG_BEST
, FALSE
, 0, 0, 0);
988 if (context
&& !secret
.isEmpty()) {
989 otrSetTrust(aUNI
, false);
990 QByteArray
ba(secret
.toUtf8());
991 if (!question
.isEmpty()) {
992 QByteArray
ba1(question
.toUtf8());
993 otrl_message_initiate_smp_q(mOTRState
, &ops
, (void *)this, context
, ba1
.constData(), (const unsigned char *)ba
.constData(), ba
.size());
995 otrl_message_initiate_smp(mOTRState
, &ops
, (void *)this, context
, (const unsigned char *)ba
.constData(), ba
.size());
1002 void ChatForm::deactivateAllOTR () {
1003 foreach (PsycContact
*cc
, mContactList
) {
1004 cc
->setOTRVerified(false);
1005 if (cc
->isOTRActive()) {
1006 cc
->setOTRActive(false);
1013 void ChatForm::disconnectAllOTR () {
1017 ConnContext
*context
= mOTRState
->context_root
;
1019 ConnContext
*next
= context
->next
;
1020 if (context
->msgstate
== OTRL_MSGSTATE_ENCRYPTED
&& context
->protocol_version
> 1) {
1021 otrDisconnect(context
->username
);
1022 //otrl_message_disconnect(mOTRState, &ops, (void *)this, context->accountname, context->protocol, context->username);
1031 void ChatForm::otrDisconnect (const QString
&uni
) {
1033 QByteArray
user(uni
.toLower().toUtf8());
1034 QByteArray
me(mProto
->uni().toLower().toUtf8());
1035 dlogf(" sending OTR disconnect to [%s]", user
.constData());
1036 otrl_message_disconnect(mOTRState
, &ops
, (void *)this, me
, PROTO_NAME
, user
, OTRL_INSTAG_BEST
);
1041 PsycContact *cc = findContact(uni);
1042 if (cc && cc->isOTRActive()) {
1043 cc->setOTRActive(false);
1050 void ChatForm::otrConnect (const QString
&uni
) {
1052 QByteArray
me(mProto
->uni().toLower().toUtf8());
1053 QByteArray
to(uni
.toLower().toUtf8());
1054 dlogf("------------------- STARTING OTR WITH %s -------------------", to
.constData());
1055 //char *msg = otrDefaultQueryMsg(me.constData(), OTRL_POLICY_OPPORTUNISTIC);
1056 //otrSendMessageCB((void *)this, me.constData(), PROTO_NAME, to.constData(), (msg ? msg : "?OTRv2?"));
1057 //if (msg) free(msg);
1060 //ConnContext *context;
1061 err
= otrl_message_sending(mOTRState
, &ops
, (void *)this, me
, PROTO_NAME
, to
,
1062 OTRL_INSTAG_BEST
, // instag
1064 NULL
, // no additional TLVs
1066 /*OTRL_FRAGMENT_SEND_SKIP*/OTRL_FRAGMENT_SEND_ALL
, // fragmentation policy
1068 NULL
, // add_appdata callback
1072 dlogf("failure to encrypt message!\n");
1076 dlogf("WTF?! an empty OTR resulting message!\n");
1077 //mProto->sendMessage(uni, txt, act);
1080 //QByteArray mx(newMsg);
1081 //mProto->sendMessage(uni, mx, act);
1083 ConnContext *context = otrl_context_find(mOTRState, to, me, PROTO_NAME, OTRL_INSTAG_BEST, FALSE, 0, 0, 0);
1086 err = otrl_message_fragment_and_send(&ops, (void *)this, context, newMsg, OTRL_FRAGMENT_SEND_ALL, &frag);
1087 if (frag) free(frag);
1089 dlogf("WTF?! no context found for otrl_message_fragment_and_send()\n");
1092 otrl_message_free(newMsg
);
1100 void ChatForm::restartOTRTimer (unsigned int interval
) {
1102 if (interval
> 0) mOTRTimer
->start(interval
*1000);
1106 void ChatForm::onOTRTimer () {
1107 if (mOTRState
) otrl_message_poll(mOTRState
, &ops
, (void *)this);