comparison mcabber/mcabber/otr.c @ 1668:41c26b7d2890

Install mcabber headers * Change mcabber headers naming scheme * Move 'src/' -> 'mcabber/' * Add missing include <mcabber/config.h>'s * Create and install clean config.h version in 'include/' * Move "dirty" config.h version to 'mcabber/' * Add $(top_srcdir) to compiler include path * Update modules HOWTO
author Myhailo Danylenko <isbear@ukrpost.net>
date Mon, 18 Jan 2010 15:36:19 +0200
parents mcabber/src/otr.c@f4a2c6f767d1
children e6e89b1d7831
comparison
equal deleted inserted replaced
1667:8af0e0ad20ad 1668:41c26b7d2890
1 /*
2 * otr.c -- Off-The-Record Messaging for mcabber
3 *
4 * Copyright (C) 2007-2009 Frank Zschockelt <mcabber_otr@freakysoft.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or (at
9 * your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 * USA
20 */
21
22 #include <config.h>
23 #include <glib.h>
24
25 #ifdef HAVE_LIBOTR
26
27 #include "hbuf.h"
28 #include "logprint.h"
29 #include "nohtml.h"
30 #include "otr.h"
31 #include "roster.h"
32 #include "screen.h"
33 #include "settings.h"
34 #include "utils.h"
35 #include "xmpp.h"
36
37 #define OTR_PROTOCOL_NAME "jabber"
38
39 static OtrlUserState userstate = NULL;
40 static char *account = NULL;
41 static char *keyfile = NULL;
42 static char *fprfile = NULL;
43
44 static int otr_is_enabled = FALSE;
45
46 static OtrlPolicy cb_policy (void *opdata, ConnContext *ctx);
47 static void cb_create_privkey (void *opdata,
48 const char *accountname,
49 const char *protocol);
50 static int cb_is_logged_in (void *opdata,
51 const char *accountname,
52 const char *protocol,
53 const char *recipient);
54 static void cb_inject_message (void *opdata,
55 const char *accountname,
56 const char *protocol,
57 const char *recipient,
58 const char *message);
59 static void cb_notify (void *opdata,
60 OtrlNotifyLevel level,
61 const char *accountname,
62 const char *protocol,
63 const char *username,
64 const char *title,
65 const char *primary,
66 const char *secondary);
67 static int cb_display_otr_message(void *opdata,
68 const char *accountname,
69 const char *protocol,
70 const char *username,
71 const char *msg);
72 static void cb_update_context_list(void *opdata);
73 static const char *cb_protocol_name (void *opdata, const char *protocol);
74 static void cb_protocol_name_free (void *opdata,
75 const char *protocol_name);
76 static void cb_new_fingerprint (void *opdata, OtrlUserState us,
77 const char *accountname,
78 const char *protocol,
79 const char *username,
80 unsigned char fingerprint[20]);
81 static void cb_write_fingerprints (void *opdata);
82 static void cb_gone_secure (void *opdata, ConnContext *context);
83 static void cb_gone_insecure (void *opdata, ConnContext *context);
84 static void cb_still_secure (void *opdata, ConnContext *context,
85 int is_reply);
86 static void cb_log_message (void *opdata, const char *message);
87 static int cb_max_message_size (void *opdata, ConnContext *context);
88
89 static OtrlMessageAppOps ops =
90 {
91 cb_policy,
92 cb_create_privkey,
93 cb_is_logged_in,
94 cb_inject_message,
95 cb_notify,
96 cb_display_otr_message,
97 cb_update_context_list,
98 cb_protocol_name,
99 cb_protocol_name_free,
100 cb_new_fingerprint,
101 cb_write_fingerprints,
102 cb_gone_secure,
103 cb_gone_insecure,
104 cb_still_secure,
105 cb_log_message,
106 cb_max_message_size,
107 NULL, /*account_name*/
108 NULL /*account_name_free*/
109 };
110
111 static void otr_message_disconnect(ConnContext *ctx);
112 static ConnContext *otr_get_context(const char *buddy);
113 static void otr_startstop(const char *buddy, int start);
114 static void otr_handle_smp_tlvs(OtrlTLV *tlvs, ConnContext *ctx);
115
116 static char *otr_get_dir(void);
117
118 void otr_init(const char *fjid)
119 {
120 char *root;
121
122 if (userstate) //already initialised
123 return;
124
125 otr_is_enabled = !!settings_opt_get_int("otr");
126
127 if (!otr_is_enabled)
128 return;
129
130 OTRL_INIT;
131
132 userstate = otrl_userstate_create();
133
134 root = otr_get_dir();
135 account = jidtodisp(fjid);
136 keyfile = g_strdup_printf("%s%s.key", root, account);
137 fprfile = g_strdup_printf("%s%s.fpr", root, account);
138 g_free(root);
139
140 if (otrl_privkey_read(userstate, keyfile)){
141 scr_LogPrint(LPRINT_LOGNORM, "Could not read OTR key from %s", keyfile);
142 cb_create_privkey(NULL, account, OTR_PROTOCOL_NAME);
143 }
144 if (otrl_privkey_read_fingerprints(userstate, fprfile, NULL, NULL)){
145 scr_LogPrint(LPRINT_LOGNORM, "Could not read OTR fingerprints from %s",
146 fprfile);
147 }
148 }
149
150 void otr_terminate(void)
151 {
152 ConnContext *ctx;
153
154 if (!otr_is_enabled)
155 return;
156
157 for (ctx = userstate->context_root; ctx; ctx = ctx->next)
158 if (ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED)
159 otr_message_disconnect(ctx);
160
161 g_free(account);
162 account = NULL;
163
164 /* XXX This #ifdef is a quick workaround: when mcabber
165 * is linked to both gnutls and libotr, libgcrypt will
166 * segfault when we call otrl_userstate_free().
167 * This is reported to be a bug in libgcrypt :-/
168 * Mikael
169 */
170 #if defined(HAVE_GNUTLS) && !defined(HAVE_OPENSSL) //TODO: broken now
171 if (!settings_opt_get_int("ssl"))
172 #endif
173 otrl_userstate_free(userstate);
174
175 userstate = NULL;
176 g_free(keyfile);
177 keyfile = NULL;
178 }
179
180 static char *otr_get_dir(void)
181 {
182 const char *configured_dir = settings_opt_get("otr_dir");
183
184 if (configured_dir && *configured_dir) {
185 char *xp_conf_dir;
186 int l;
187 xp_conf_dir = expand_filename(configured_dir);
188 // The path must be slash-terminated
189 l = strlen(xp_conf_dir);
190 if (xp_conf_dir[l-1] != '/') {
191 char *xp_conf_dir_tmp = xp_conf_dir;
192 xp_conf_dir = g_strdup_printf("%s/", xp_conf_dir_tmp);
193 g_free(xp_conf_dir_tmp);
194 }
195 return xp_conf_dir;
196 } else {
197 return expand_filename("~/.mcabber/otr/");
198 }
199 }
200
201 static ConnContext *otr_get_context(const char *buddy)
202 {
203 int null = 0;
204 ConnContext *ctx;
205 char *lowcasebuddy = g_strdup(buddy);
206
207 mc_strtolower(lowcasebuddy);
208 ctx = otrl_context_find(userstate, lowcasebuddy, account, OTR_PROTOCOL_NAME,
209 1, &null, NULL, NULL);
210 g_free(lowcasebuddy);
211 return ctx;
212 }
213
214 static void otr_message_disconnect(ConnContext *ctx)
215 {
216 if (ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED)
217 cb_gone_insecure(NULL, ctx);
218 otrl_message_disconnect(userstate, &ops, NULL, ctx->accountname,
219 ctx->protocol, ctx->username);
220 }
221
222 static void otr_startstop(const char *buddy, int start)
223 {
224 char *msg = NULL;
225 ConnContext *ctx = otr_get_context(buddy);
226
227 if (!userstate || !ctx)
228 return;
229
230 if (start && ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED)
231 otr_message_disconnect(ctx);
232
233 if (start) {
234 OtrlPolicy policy = cb_policy(NULL, ctx);
235 if (policy == plain) {
236 scr_LogPrint(LPRINT_LOGNORM, "The OTR policy for this user is set to"
237 " plain. You have to change it first.");
238 return;
239 }
240 msg = otrl_proto_default_query_msg(ctx->accountname, policy);
241 cb_inject_message(NULL, ctx->accountname, ctx->protocol, ctx->username,
242 msg);
243 free (msg);
244 }
245 else
246 otr_message_disconnect(ctx);
247 }
248
249 void otr_establish(const char *buddy)
250 {
251 otr_startstop(buddy, 1);
252 }
253
254 void otr_disconnect(const char *buddy)
255 {
256 otr_startstop(buddy, 0);
257 }
258
259 void otr_fingerprint(const char *buddy, const char *trust)
260 {
261 char fpr[45], *tr;
262 ConnContext *ctx = otr_get_context(buddy);
263 if (!userstate || !ctx)
264 return;
265
266 if (!ctx->active_fingerprint || !ctx->active_fingerprint->fingerprint) {
267 scr_LogPrint(LPRINT_LOGNORM,
268 "No active fingerprint - start OTR for this buddy first.");
269 return;
270 }
271
272 otrl_privkey_hash_to_human(fpr, ctx->active_fingerprint->fingerprint);
273 if (trust) {
274 if (strcmp(fpr, trust) == 0)
275 otrl_context_set_trust(ctx->active_fingerprint, "trust");
276 else
277 otrl_context_set_trust(ctx->active_fingerprint, NULL);
278 }
279
280 tr = ctx->active_fingerprint->trust;
281 scr_LogPrint(LPRINT_LOGNORM, "%s [%44s]: %s", ctx->username, fpr,
282 tr && *tr ? "trusted" : "untrusted");
283 cb_write_fingerprints(NULL);
284 }
285
286 static void otr_handle_smp_tlvs(OtrlTLV *tlvs, ConnContext *ctx)
287 {
288 OtrlTLV *tlv = NULL;
289 char *sbuf = NULL;
290 NextExpectedSMP nextMsg = ctx->smstate->nextExpected;
291
292 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1);
293 if (tlv) {
294 if (nextMsg != OTRL_SMP_EXPECT1)
295 otr_smp_abort(ctx->username);
296 else {
297 sbuf = g_strdup_printf("OTR: Received SMP Initiation. "
298 "Answer with /otr smpr %s $secret",
299 ctx->username);
300 }
301 }
302 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2);
303 if (tlv) {
304 if (nextMsg != OTRL_SMP_EXPECT2)
305 otr_smp_abort(ctx->username);
306 else {
307 sbuf = g_strdup("OTR: Received SMP Response.");
308 /* If we received TLV2, we will send TLV3 and expect TLV4 */
309 ctx->smstate->nextExpected = OTRL_SMP_EXPECT4;
310 }
311 }
312 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3);
313 if (tlv) {
314 if (nextMsg != OTRL_SMP_EXPECT3)
315 otr_smp_abort(ctx->username);
316 else {
317 /* If we received TLV3, we will send TLV4
318 * We will not expect more messages, so prepare for next SMP */
319 ctx->smstate->nextExpected = OTRL_SMP_EXPECT1;
320 /* Report result to user */
321 if (ctx->active_fingerprint && ctx->active_fingerprint->trust &&
322 *ctx->active_fingerprint->trust != '\0')
323 sbuf = g_strdup("OTR: SMP succeeded");
324 else
325 sbuf = g_strdup("OTR: SMP failed");
326 }
327 }
328 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4);
329 if (tlv) {
330 if (nextMsg != OTRL_SMP_EXPECT4)
331 otr_smp_abort(ctx->username);
332 else {
333 /* We will not expect more messages, so prepare for next SMP */
334 ctx->smstate->nextExpected = OTRL_SMP_EXPECT1;
335 /* Report result to user */
336 if (ctx->active_fingerprint && ctx->active_fingerprint->trust &&
337 *ctx->active_fingerprint->trust != '\0')
338 sbuf = g_strdup("OTR: SMP succeeded");
339 else
340 sbuf = g_strdup("OTR: SMP failed");
341 }
342 }
343 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP_ABORT);
344 if (tlv) {
345 /* The message we are waiting for will not arrive, so reset
346 * and prepare for the next SMP */
347 sbuf = g_strdup("OTR: SMP aborted by your buddy");
348 ctx->smstate->nextExpected = OTRL_SMP_EXPECT1;
349 }
350
351 if (sbuf) {
352 scr_WriteIncomingMessage(ctx->username, sbuf, 0, HBB_PREFIX_INFO, 0);
353 g_free(sbuf);
354 }
355 }
356
357 /*
358 * returns whether a otr_message was received
359 * sets *otr_data to NULL, when it was an internal otr message
360 */
361 int otr_receive(char **otr_data, const char *buddy, int *free_msg)
362 {
363 int ignore_message;
364 char *newmessage = NULL;
365 OtrlTLV *tlvs = NULL;
366 OtrlTLV *tlv = NULL;
367 ConnContext *ctx;
368
369 ctx = otr_get_context(buddy);
370 *free_msg = 0;
371 ignore_message = otrl_message_receiving(userstate, &ops, NULL,
372 ctx->accountname, ctx->protocol,
373 ctx->username, *otr_data,
374 &newmessage, &tlvs,NULL, NULL);
375
376
377 tlv = otrl_tlv_find(tlvs, OTRL_TLV_DISCONNECTED);
378 if (tlv) {
379 /* Notify the user that the other side disconnected. */
380 if (ctx) {
381 cb_gone_insecure(NULL, ctx);
382 otr_disconnect(ctx->username);
383 }
384 }
385
386 otr_handle_smp_tlvs(tlvs, ctx);
387
388 if (tlvs != NULL)
389 otrl_tlv_free(tlvs);
390
391 if (ignore_message)
392 *otr_data = NULL;
393
394 if (!ignore_message && newmessage) {
395 *free_msg = 1;
396 *otr_data = html_strip(newmessage);
397 otrl_message_free(newmessage);
398 if (ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED)
399 return 1;
400 }
401 return 0;
402 }
403
404 int otr_send(char **msg, const char *buddy)
405 {
406 gcry_error_t err;
407 char *newmessage = NULL;
408 char *htmlmsg;
409 ConnContext *ctx = otr_get_context(buddy);
410
411 if (ctx->msgstate == OTRL_MSGSTATE_PLAINTEXT)
412 err = otrl_message_sending(userstate, &ops, NULL, ctx->accountname,
413 ctx->protocol, ctx->username, *msg, NULL,
414 &newmessage, NULL, NULL);
415 else {
416 htmlmsg = html_escape(*msg);
417 err = otrl_message_sending(userstate, &ops, NULL, ctx->accountname,
418 ctx->protocol, ctx->username, htmlmsg, NULL,
419 &newmessage, NULL, NULL);
420 g_free(htmlmsg);
421 }
422
423 if (err)
424 *msg = NULL; /*something went wrong, don't send the plain-message! */
425
426 if (!err && newmessage) {
427 *msg = g_strdup(newmessage);
428 otrl_message_free(newmessage);
429 if (cb_policy(NULL, ctx) & OTRL_POLICY_REQUIRE_ENCRYPTION ||
430 ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED)
431 return 1;
432 }
433 return 0;
434 }
435
436 /* Prints OTR connection state */
437 void otr_print_info(const char *buddy)
438 {
439 const char *state, *auth, *policy;
440 ConnContext *ctx = otr_get_context(buddy);
441 OtrlPolicy p = cb_policy(ctx->app_data, ctx);
442
443 if (!userstate || !ctx)
444 return;
445
446 switch (ctx->msgstate) {
447 case OTRL_MSGSTATE_PLAINTEXT: state = "plaintext"; break;
448 case OTRL_MSGSTATE_ENCRYPTED:
449 switch (ctx->protocol_version) {
450 case 1: state = "encrypted V1"; break;
451 case 2: state = "encrypted V2"; break;
452 default:state = "encrypted";
453 };
454 break;
455 case OTRL_MSGSTATE_FINISHED: state = "finished"; break;
456 default: state = "unknown state";
457 }
458 switch (ctx->auth.authstate) {
459 case OTRL_AUTHSTATE_NONE:
460 switch (ctx->otr_offer) {
461 case OFFER_NOT: auth = "no offer sent"; break;
462 case OFFER_SENT: auth = "offer sent"; break;
463 case OFFER_ACCEPTED: auth = "offer accepted"; break;
464 case OFFER_REJECTED: auth = "offer rejected"; break;
465 default: auth = "unknown auth";
466 }
467 break;
468 case OTRL_AUTHSTATE_AWAITING_DHKEY:
469 auth = "awaiting D-H key"; break;
470 case OTRL_AUTHSTATE_AWAITING_REVEALSIG:
471 auth = "awaiting reveal signature"; break;
472 case OTRL_AUTHSTATE_AWAITING_SIG:
473 auth = "awaiting signature"; break;
474 case OTRL_AUTHSTATE_V1_SETUP:
475 auth = "v1 setup"; break;
476 default:
477 auth = "unknown auth";
478 }
479 if (p == OTRL_POLICY_NEVER)
480 policy = "plain";
481 else if (p == (OTRL_POLICY_OPPORTUNISTIC & ~OTRL_POLICY_ALLOW_V1))
482 policy = "opportunistic";
483 else if (p == (OTRL_POLICY_MANUAL & ~OTRL_POLICY_ALLOW_V1))
484 policy = "manual";
485 else if (p == (OTRL_POLICY_ALWAYS & ~OTRL_POLICY_ALLOW_V1))
486 policy = "always";
487 else
488 policy = "unknown";
489
490 scr_LogPrint(LPRINT_LOGNORM, "%s: %s (%s) [%s]",
491 ctx->username, state, auth, policy);
492 }
493
494 static ConnContext *otr_context_encrypted(const char *buddy)
495 {
496 ConnContext *ctx = otr_get_context(buddy);
497
498 if (!userstate || !ctx || ctx->msgstate != OTRL_MSGSTATE_ENCRYPTED){
499 scr_LogPrint(LPRINT_LOGNORM,
500 "You have to start an OTR channel with %s before you can "
501 "use SMP.", buddy);
502 return NULL;
503 }
504
505 return ctx;
506 }
507
508 void otr_smp_query(const char *buddy, const char *secret)
509 {
510 ConnContext *ctx = otr_context_encrypted(buddy);
511
512 if (!secret) {
513 scr_LogPrint(LPRINT_LOGNORM,
514 "Using SMP without a secret isn't a good idea.");
515 return;
516 }
517
518 if (ctx) {
519 otrl_message_initiate_smp(userstate, &ops, NULL, ctx,
520 (const unsigned char *)secret,
521 strlen(secret));
522 scr_WriteIncomingMessage(ctx->username,
523 "OTR: Socialist Millionaires' Protocol "
524 "initiated.", 0, HBB_PREFIX_INFO, 0);
525 }
526 }
527
528 void otr_smp_respond(const char *buddy, const char *secret)
529 {
530 ConnContext *ctx = otr_context_encrypted(buddy);
531
532 if (!secret) {
533 scr_LogPrint(LPRINT_LOGNORM,
534 "Using SMP without a secret isn't a good idea.");
535 return;
536 }
537
538 if (ctx) {
539 if (!ctx->smstate->secret) {
540 scr_LogPrint(LPRINT_LOGNORM,
541 "Don't call smpr until you have received an SMP "
542 "Initiation!");
543 return;
544 }
545 otrl_message_respond_smp(userstate, &ops, NULL, ctx,
546 (const unsigned char *)secret,
547 strlen(secret));
548 scr_WriteIncomingMessage(ctx->username,
549 "OTR: Socialist Millionaires' Protocol: "
550 "response sent", 0, HBB_PREFIX_INFO, 0);
551 }
552 }
553
554 void otr_smp_abort(const char *buddy)
555 {
556 ConnContext *ctx = otr_context_encrypted(buddy);
557
558 if (ctx) {
559 otrl_message_abort_smp(userstate, &ops, NULL, ctx);
560 scr_WriteIncomingMessage(ctx->username,
561 "OTR: Socialist Millionaires' Protocol aborted.",
562 0, HBB_PREFIX_INFO, 0);
563 }
564 }
565
566 void otr_key(void)
567 {
568 OtrlPrivKey *key;
569 char readable[45] = "";
570
571 if(!userstate)
572 return;
573 for (key = userstate->privkey_root; key; key = key->next) {
574 otrl_privkey_fingerprint(userstate, readable, key->accountname,
575 key->protocol);
576 scr_LogPrint(LPRINT_LOGNORM, "%s: %s", key->accountname, readable);
577 }
578 }
579
580 /* Return the OTR policy for the given context. */
581 static OtrlPolicy cb_policy(void *opdata, ConnContext *ctx)
582 {
583 enum otr_policy p = settings_otr_getpolicy(NULL);
584
585 if(ctx)
586 if(settings_otr_getpolicy(ctx->username))
587 p = settings_otr_getpolicy(ctx->username);
588
589 switch (p) {
590 case plain:
591 return OTRL_POLICY_NEVER;
592 case opportunistic:
593 return OTRL_POLICY_OPPORTUNISTIC & ~OTRL_POLICY_ALLOW_V1;
594 case manual:
595 return OTRL_POLICY_MANUAL & ~OTRL_POLICY_ALLOW_V1;
596 case always:
597 return OTRL_POLICY_ALWAYS & ~OTRL_POLICY_ALLOW_V1;
598 }
599
600 return OTRL_POLICY_MANUAL & ~OTRL_POLICY_ALLOW_V1;
601 }
602
603 /* Create a private key for the given accountname/protocol if
604 * desired. */
605 static void cb_create_privkey(void *opdata, const char *accountname,
606 const char *protocol)
607 {
608 gcry_error_t e;
609 char *root;
610
611 scr_LogPrint(LPRINT_LOGNORM,
612 "Generating new OTR key for %s. This may take a while...",
613 accountname);
614 scr_DoUpdate();
615
616 e = otrl_privkey_generate(userstate, keyfile, accountname, protocol);
617
618 if (e) {
619 root = otr_get_dir();
620 scr_LogPrint(LPRINT_LOGNORM, "OTR key generation failed! Please mkdir "
621 "%s if you want to use otr encryption.", root);
622 g_free(root);
623 }
624 else
625 scr_LogPrint(LPRINT_LOGNORM, "OTR key generated.");
626 }
627
628 /* Report whether you think the given user is online. Return 1 if
629 * you think he is, 0 if you think he isn't, -1 if you're not sure.
630 * If you return 1, messages such as heartbeats or other
631 * notifications may be sent to the user, which could result in "not
632 * logged in" errors if you're wrong. */
633 static int cb_is_logged_in(void *opdata, const char *accountname,
634 const char *protocol, const char *recipient)
635 {
636 int ret = (roster_getstatus(recipient, NULL) != offline);
637 return ret;
638 }
639
640 /* Send the given IM to the given recipient from the given
641 * accountname/protocol. */
642 static void cb_inject_message(void *opdata, const char *accountname,
643 const char *protocol, const char *recipient,
644 const char *message)
645 {
646 if (roster_gettype(recipient) == ROSTER_TYPE_USER)
647 xmpp_send_msg(recipient, message, ROSTER_TYPE_USER, "", TRUE, NULL,
648 LM_MESSAGE_SUB_TYPE_NOT_SET, NULL);
649 }
650
651 /* Display a notification message for a particular
652 * accountname / protocol / username conversation. */
653 static void cb_notify(void *opdata, OtrlNotifyLevel level,
654 const char *accountname, const char *protocol,
655 const char *username, const char *title,
656 const char *primary, const char *secondary)
657 {
658 char *type;
659 char *sbuf = NULL;
660 switch (level) {
661 case OTRL_NOTIFY_ERROR: type = "error"; break;
662 case OTRL_NOTIFY_WARNING: type = "warning"; break;
663 case OTRL_NOTIFY_INFO: type = "info"; break;
664 default: type = "unknown";
665 }
666 sbuf = g_strdup_printf("OTR %s:%s\n%s\n%s",type,title, primary, secondary);
667 scr_WriteIncomingMessage(username, sbuf, 0, HBB_PREFIX_INFO, 0);
668 g_free(sbuf);
669 }
670
671 /* Display an OTR control message for a particular
672 * accountname / protocol / username conversation. Return 0 if you are able
673 * to successfully display it. If you return non-0 (or if this
674 * function is NULL), the control message will be displayed inline,
675 * as a received message, or else by using the above notify()
676 * callback. */
677 static int cb_display_otr_message(void *opdata, const char *accountname,
678 const char *protocol, const char *username,
679 const char *msg)
680 {
681 char *strippedmsg = html_strip(msg);
682 scr_WriteIncomingMessage(username, strippedmsg, 0, HBB_PREFIX_INFO, 0);
683 g_free(strippedmsg);
684 return 0;
685 }
686
687 /* When the list of ConnContexts changes (including a change in
688 * state), this is called so the UI can be updated. */
689 static void cb_update_context_list(void *opdata)
690 {
691 /*maybe introduce new status characters for mcabber,
692 * then use this function (?!)*/
693 }
694
695 /* Return a newly allocated string containing a human-friendly name
696 * for the given protocol id */
697 static const char *cb_protocol_name(void *opdata, const char *protocol)
698 {
699 return protocol;
700 }
701
702 /* Deallocate a string allocated by protocol_name */
703 static void cb_protocol_name_free (void *opdata, const char *protocol_name)
704 {
705 /* We didn't allocated memory, so we don't have to free anything :p */
706 }
707
708 /* A new fingerprint for the given user has been received. */
709 static void cb_new_fingerprint(void *opdata, OtrlUserState us,
710 const char *accountname, const char *protocol,
711 const char *username,
712 unsigned char fingerprint[20])
713 {
714 char *sbuf = NULL;
715 char readable[45];
716
717 otrl_privkey_hash_to_human(readable, fingerprint);
718 sbuf = g_strdup_printf("OTR: new fingerprint: %s", readable);
719 scr_WriteIncomingMessage(username, sbuf, 0, HBB_PREFIX_INFO, 0);
720 g_free(sbuf);
721 }
722
723 /* The list of known fingerprints has changed. Write them to disk. */
724 static void cb_write_fingerprints(void *opdata)
725 {
726 otrl_privkey_write_fingerprints(userstate, fprfile);
727 }
728
729 /* A ConnContext has entered a secure state. */
730 static void cb_gone_secure(void *opdata, ConnContext *context)
731 {
732 scr_WriteIncomingMessage(context->username, "OTR: channel established", 0,
733 HBB_PREFIX_INFO, 0);
734 }
735
736 /* A ConnContext has left a secure state. */
737 static void cb_gone_insecure(void *opdata, ConnContext *context)
738 {
739 scr_WriteIncomingMessage(context->username, "OTR: channel closed", 0,
740 HBB_PREFIX_INFO, 0);
741 }
742
743 /* We have completed an authentication, using the D-H keys we
744 * already knew. is_reply indicates whether we initiated the AKE. */
745 static void cb_still_secure(void *opdata, ConnContext *context, int is_reply)
746 {
747 scr_WriteIncomingMessage(context->username, "OTR: channel reestablished", 0,
748 HBB_PREFIX_INFO, 0);
749 }
750
751 /* Log a message. The passed message will end in "\n". */
752 static void cb_log_message(void *opdata, const char *message)
753 {
754 scr_LogPrint(LPRINT_DEBUG, "OTR: %s", message);
755 }
756
757 /* Find the maximum message size supported by this protocol. */
758 static int cb_max_message_size(void *opdata, ConnContext *context)
759 {
760 return 8192;
761 }
762
763 int otr_enabled(void)
764 {
765 return otr_is_enabled;
766 }
767
768 #else /* !HAVE_LIBOTR */
769
770 int otr_enabled(void)
771 {
772 return FALSE;
773 }
774
775 #endif /* HAVE_LIBOTR */
776
777 /* vim: set expandtab cindent cinoptions=>2\:2(0: For Vim users... */