Mercurial > ~mikael > mcabber > hg
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... */ |