Mercurial > ~mikael > mcabber > hg
comparison mcabber/src/otr.c @ 1299:3b338a5c01fc
OTR support
author | Frank Zschockelt <mcabber_otr[at]freakysoft.de> |
---|---|
date | Thu, 30 Aug 2007 00:52:51 +0200 |
parents | |
children | 37b41ed9ed35 |
comparison
equal
deleted
inserted
replaced
1298:af035a304bec | 1299:3b338a5c01fc |
---|---|
1 /* | |
2 * otr.c -- Off-The-Record Messaging for mcabber | |
3 * | |
4 * Copyright (C) 2007 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 | |
24 #ifdef HAVE_LIBOTR | |
25 | |
26 #include "otr.h" | |
27 #include "logprint.h" | |
28 #include "hbuf.h" | |
29 #include "jab_priv.h" | |
30 #include "roster.h" | |
31 #include "utils.h" | |
32 | |
33 | |
34 static OtrlUserState userstate = NULL; | |
35 static char * account = NULL; | |
36 static char * keyfile = NULL; | |
37 static char * fprfile = NULL; | |
38 static enum otr_policy policy = manual; | |
39 | |
40 | |
41 static OtrlPolicy cb_policy (void *opdata, ConnContext *ctx); | |
42 static void cb_create_privkey (void *opdata, | |
43 const char *accountname, | |
44 const char *protocol); | |
45 static int cb_is_logged_in (void *opdata, | |
46 const char *accountname, | |
47 const char *protocol, | |
48 const char *recipient); | |
49 static void cb_inject_message (void *opdata, | |
50 const char *accountname, | |
51 const char *protocol, | |
52 const char *recipient, | |
53 const char *message); | |
54 static void cb_notify (void *opdata, | |
55 OtrlNotifyLevel level, | |
56 const char *accountname, | |
57 const char *protocol, | |
58 const char *username, | |
59 const char *title, | |
60 const char *primary, | |
61 const char *secondary); | |
62 static int cb_display_otr_message(void *opdata, | |
63 const char *accountname, | |
64 const char *protocol, | |
65 const char *username, | |
66 const char *msg); | |
67 static void cb_update_context_list(void *opdata); | |
68 static const char *cb_protocol_name (void *opdata, const char *protocol); | |
69 static void cb_protocol_name_free (void *opdata, | |
70 const char *protocol_name); | |
71 static void cb_new_fingerprint (void *opdata, OtrlUserState us, | |
72 const char *accountname, | |
73 const char *protocol, | |
74 const char *username, | |
75 unsigned char fingerprint[20]); | |
76 static void cb_write_fingerprints (void *opdata); | |
77 static void cb_gone_secure (void *opdata, ConnContext *context); | |
78 static void cb_gone_insecure (void *opdata, ConnContext *context); | |
79 static void cb_still_secure (void *opdata, ConnContext *context, | |
80 int is_reply); | |
81 static void cb_log_message (void *opdata, const char *message); | |
82 static int cb_max_message_size (void *opdata, ConnContext *context); | |
83 | |
84 static OtrlMessageAppOps ops = | |
85 { | |
86 policy: cb_policy, | |
87 create_privkey: cb_create_privkey, | |
88 is_logged_in: cb_is_logged_in, | |
89 inject_message: cb_inject_message, | |
90 notify: cb_notify, | |
91 display_otr_message: cb_display_otr_message, | |
92 update_context_list: cb_update_context_list, | |
93 protocol_name: cb_protocol_name, | |
94 protocol_name_free: cb_protocol_name_free, | |
95 new_fingerprint: cb_new_fingerprint, | |
96 write_fingerprints: cb_write_fingerprints, | |
97 gone_secure: cb_gone_secure, | |
98 gone_insecure: cb_gone_insecure, | |
99 still_secure: cb_still_secure, | |
100 log_message: cb_log_message, | |
101 max_message_size: cb_max_message_size | |
102 }; | |
103 | |
104 static void otr_message_disconnect(ConnContext *ctx); | |
105 static ConnContext * otr_get_context(const char *buddy); | |
106 static void otr_startstop(const char * buddy, int start); | |
107 static void otr_handle_smp_tlvs(OtrlTLV * tlvs, ConnContext * ctx); | |
108 | |
109 | |
110 int otr_init(const char *jid) | |
111 { | |
112 char * root = expand_filename("~/.mcabber/otr/"); | |
113 account = jidtodisp(jid); | |
114 keyfile = g_strdup_printf("%s%s.key", root, account); | |
115 fprfile = g_strdup_printf("%s%s.fpr", root, account); | |
116 g_free(root); | |
117 | |
118 OTRL_INIT; | |
119 | |
120 userstate = otrl_userstate_create (); | |
121 if (otrl_privkey_read(userstate, keyfile)){ | |
122 scr_LogPrint(LPRINT_LOGNORM, "Could not read OTR key from %s", keyfile); | |
123 cb_create_privkey(NULL, account, "jabber"); | |
124 } | |
125 if (otrl_privkey_read_fingerprints(userstate, fprfile, NULL, NULL)){ | |
126 scr_LogPrint(LPRINT_LOGNORM, "Could not read OTR fingerprints from %s", | |
127 fprfile); | |
128 } | |
129 } | |
130 | |
131 void otr_terminate(void) | |
132 { | |
133 ConnContext * ctx; | |
134 | |
135 for(ctx = userstate->context_root; ctx; ctx = ctx->next) | |
136 if (ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) | |
137 otr_message_disconnect(ctx); | |
138 | |
139 g_free(account); | |
140 account = NULL; | |
141 otrl_userstate_free(userstate); | |
142 userstate = NULL; | |
143 g_free(keyfile); | |
144 keyfile = NULL; | |
145 } | |
146 | |
147 static ConnContext * otr_get_context(const char *buddy) | |
148 { | |
149 int null = 0; | |
150 return otrl_context_find(userstate, buddy, account, "jabber", 1, &null, | |
151 NULL, NULL); | |
152 } | |
153 | |
154 static void otr_message_disconnect(ConnContext *ctx) | |
155 { | |
156 if (ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) | |
157 cb_gone_insecure(NULL, ctx); | |
158 otrl_message_disconnect(userstate, &ops, NULL, ctx->accountname, | |
159 ctx->protocol, ctx->username); | |
160 } | |
161 | |
162 static void otr_startstop(const char * buddy, int start) | |
163 { | |
164 char * msg = NULL; | |
165 ConnContext *ctx = otr_get_context(buddy); | |
166 | |
167 if (!userstate || !ctx) | |
168 return; | |
169 | |
170 if (start && ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) | |
171 otr_message_disconnect(ctx); | |
172 | |
173 if (start) { | |
174 OtrlPolicy policy = cb_policy(NULL, ctx); | |
175 msg = otrl_proto_default_query_msg(ctx->accountname, policy); | |
176 cb_inject_message(NULL, ctx->accountname, ctx->protocol, ctx->username, | |
177 msg); | |
178 free (msg); | |
179 } | |
180 else | |
181 otr_message_disconnect(ctx); | |
182 } | |
183 | |
184 void otr_establish(const char *buddy) | |
185 { | |
186 otr_startstop(buddy, 1); | |
187 } | |
188 | |
189 void otr_disconnect(const char * buddy) | |
190 { | |
191 otr_startstop(buddy, 0); | |
192 } | |
193 | |
194 void otr_fingerprint(const char * buddy, const char * trust) | |
195 { | |
196 char fpr[45], *tr; | |
197 ConnContext *ctx = otr_get_context(buddy); | |
198 if (!userstate || !ctx) | |
199 return; | |
200 | |
201 if (!ctx->active_fingerprint || !ctx->active_fingerprint->fingerprint) { | |
202 scr_LogPrint(LPRINT_LOGNORM, | |
203 "No active fingerprint - start OTR for this buddy first."); | |
204 return; | |
205 } | |
206 | |
207 otrl_privkey_hash_to_human(fpr, ctx->active_fingerprint->fingerprint); | |
208 if (trust) { | |
209 if (strcmp(fpr, trust) == 0) | |
210 otrl_context_set_trust(ctx->active_fingerprint, "trust"); | |
211 else | |
212 otrl_context_set_trust(ctx->active_fingerprint, NULL); | |
213 } | |
214 | |
215 tr = ctx->active_fingerprint->trust; | |
216 scr_LogPrint(LPRINT_LOGNORM, "%s [%44s]: %s", ctx->username, fpr, | |
217 tr && *tr ? "trusted" : "untrusted"); | |
218 cb_write_fingerprints(NULL); | |
219 } | |
220 | |
221 static void otr_handle_smp_tlvs(OtrlTLV * tlvs, ConnContext * ctx) | |
222 { | |
223 OtrlTLV *tlv = NULL; | |
224 char *sbuf = NULL; | |
225 NextExpectedSMP nextMsg = ctx->smstate->nextExpected; | |
226 | |
227 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1); | |
228 if (tlv) { | |
229 if (nextMsg != OTRL_SMP_EXPECT1) | |
230 otr_smp_abort(ctx->username); | |
231 else { | |
232 sbuf = g_strdup_printf("OTR: Received SMP Initiation. " | |
233 "Answer with /otr smpr %s $secret", | |
234 ctx->username); | |
235 } | |
236 } | |
237 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2); | |
238 if (tlv) { | |
239 if (nextMsg != OTRL_SMP_EXPECT2) | |
240 otr_smp_abort(ctx->username); | |
241 else { | |
242 sbuf = g_strdup("OTR: Received SMP Response."); | |
243 /* If we received TLV2, we will send TLV3 and expect TLV4 */ | |
244 ctx->smstate->nextExpected = OTRL_SMP_EXPECT4; | |
245 } | |
246 } | |
247 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3); | |
248 if (tlv) { | |
249 if (nextMsg != OTRL_SMP_EXPECT3) | |
250 otr_smp_abort(ctx->username); | |
251 else { | |
252 /* If we received TLV3, we will send TLV4 | |
253 * We will not expect more messages, so prepare for next SMP */ | |
254 ctx->smstate->nextExpected = OTRL_SMP_EXPECT1; | |
255 /* Report result to user */ | |
256 if (ctx->active_fingerprint && ctx->active_fingerprint->trust && | |
257 *ctx->active_fingerprint->trust != '\0') | |
258 sbuf = g_strdup("OTR: SMP succeeded"); | |
259 else | |
260 sbuf = g_strdup("OTR: SMP failed"); | |
261 } | |
262 } | |
263 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4); | |
264 if (tlv) { | |
265 if (nextMsg != OTRL_SMP_EXPECT4) | |
266 otr_smp_abort(ctx->username); | |
267 else { | |
268 /* We will not expect more messages, so prepare for next SMP */ | |
269 ctx->smstate->nextExpected = OTRL_SMP_EXPECT1; | |
270 /* Report result to user */ | |
271 if (ctx->active_fingerprint && ctx->active_fingerprint->trust && | |
272 *ctx->active_fingerprint->trust != '\0') | |
273 sbuf = g_strdup("OTR: SMP succeeded"); | |
274 else | |
275 sbuf = g_strdup("OTR: SMP failed"); | |
276 } | |
277 } | |
278 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP_ABORT); | |
279 if (tlv) { | |
280 /* The message we are waiting for will not arrive, so reset | |
281 * and prepare for the next SMP */ | |
282 sbuf = g_strdup("OTR: SMP aborted by your buddy"); | |
283 ctx->smstate->nextExpected = OTRL_SMP_EXPECT1; | |
284 } | |
285 | |
286 if (sbuf) { | |
287 scr_WriteIncomingMessage(ctx->username, sbuf, 0, HBB_PREFIX_INFO); | |
288 g_free(sbuf); | |
289 } | |
290 } | |
291 | |
292 /* | |
293 * returns whether a otr_message was received | |
294 * sets *otr_data to NULL, when it was an internal otr message | |
295 */ | |
296 int otr_receive(char **otr_data, const char * buddy, int * free_msg) | |
297 { | |
298 int ignore_message; | |
299 char *newmessage = NULL; | |
300 OtrlTLV *tlvs = NULL; | |
301 OtrlTLV *tlv = NULL; | |
302 ConnContext * ctx; | |
303 | |
304 *free_msg = 0; | |
305 ignore_message = otrl_message_receiving(userstate, &ops, NULL, account, | |
306 "jabber", buddy, *otr_data, &newmessage, &tlvs, NULL, NULL); | |
307 | |
308 ctx = otr_get_context(buddy); | |
309 | |
310 tlv = otrl_tlv_find(tlvs, OTRL_TLV_DISCONNECTED); | |
311 if (tlv) { | |
312 /* Notify the user that the other side disconnected. */ | |
313 if (ctx) { | |
314 cb_gone_insecure(NULL, ctx); | |
315 otr_disconnect(buddy); | |
316 } | |
317 } | |
318 | |
319 otr_handle_smp_tlvs(tlvs, ctx); | |
320 | |
321 if (tlvs != NULL) | |
322 otrl_tlv_free(tlvs); | |
323 | |
324 if (ignore_message) | |
325 *otr_data = NULL; | |
326 | |
327 if (!ignore_message && newmessage) { | |
328 *free_msg = 1; | |
329 *otr_data = g_strdup(newmessage); | |
330 otrl_message_free(newmessage); | |
331 if (ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) | |
332 return 1; | |
333 } | |
334 return 0; | |
335 } | |
336 | |
337 int otr_send(char **msg, const char *buddy) | |
338 { | |
339 gcry_error_t err; | |
340 char *newmessage = NULL; | |
341 ConnContext * ctx = otr_get_context(buddy); | |
342 | |
343 err = otrl_message_sending(userstate, &ops, NULL, account, "jabber", buddy, | |
344 *msg, NULL, &newmessage, NULL, NULL); | |
345 | |
346 if (err) | |
347 *msg = NULL; /*something went wrong, don't send the plain-message! */ | |
348 | |
349 if (!err && newmessage) { | |
350 *msg = g_strdup(newmessage); | |
351 otrl_message_free(newmessage); | |
352 if (cb_policy(NULL, ctx) & OTRL_POLICY_REQUIRE_ENCRYPTION || | |
353 ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) | |
354 return 1; | |
355 } | |
356 return 0; | |
357 } | |
358 | |
359 /* Prints OTR connection state */ | |
360 void otr_print_info(const char * buddy) | |
361 { | |
362 const char *state, *auth, *policy; | |
363 ConnContext * ctx = otr_get_context(buddy); | |
364 OtrlPolicy p = cb_policy (ctx->app_data, ctx); | |
365 | |
366 if (!userstate || !ctx) | |
367 return; | |
368 | |
369 switch (ctx->msgstate) { | |
370 case OTRL_MSGSTATE_PLAINTEXT: state = "plaintext"; break; | |
371 case OTRL_MSGSTATE_ENCRYPTED: | |
372 switch (ctx->protocol_version) { | |
373 case 1: state = "encrypted V1"; break; | |
374 case 2: state = "encrypted V2"; break; | |
375 default:state = "encrypted"; | |
376 }; | |
377 break; | |
378 case OTRL_MSGSTATE_FINISHED: state = "finished"; break; | |
379 default: state = "unknown state"; | |
380 } | |
381 switch (ctx->auth.authstate) { | |
382 case OTRL_AUTHSTATE_NONE: | |
383 switch (ctx->otr_offer) { | |
384 case OFFER_NOT: auth = "no offer sent"; break; | |
385 case OFFER_SENT: auth = "offer sent"; break; | |
386 case OFFER_ACCEPTED: auth = "offer accepted"; break; | |
387 case OFFER_REJECTED: auth = "offer rejected"; break; | |
388 default: auth = "unknown auth"; | |
389 } | |
390 break; | |
391 case OTRL_AUTHSTATE_AWAITING_DHKEY: | |
392 auth = "awaiting D-H key"; break; | |
393 case OTRL_AUTHSTATE_AWAITING_REVEALSIG: | |
394 auth = "awaiting reveal signature"; break; | |
395 case OTRL_AUTHSTATE_AWAITING_SIG: | |
396 auth = "awaiting signature"; break; | |
397 case OTRL_AUTHSTATE_V1_SETUP: | |
398 auth = "v1 setup"; break; | |
399 default: | |
400 auth = "unknown auth"; | |
401 } | |
402 if (p == OTRL_POLICY_NEVER) | |
403 policy = "plain"; | |
404 else if (p == OTRL_POLICY_OPPORTUNISTIC & ~OTRL_POLICY_ALLOW_V1) | |
405 policy = "opportunistic"; | |
406 else if (p == OTRL_POLICY_MANUAL & ~OTRL_POLICY_ALLOW_V1) | |
407 policy = "manual"; | |
408 else if (p == (OTRL_POLICY_ALWAYS & ~OTRL_POLICY_ALLOW_V1)) | |
409 policy = "always"; | |
410 else | |
411 policy = "unknown"; | |
412 | |
413 scr_LogPrint(LPRINT_LOGNORM, "%s: %s (%s) [%s]", | |
414 ctx->username, state, auth, policy); | |
415 } | |
416 | |
417 static ConnContext * otr_context_encrypted(const char * buddy) | |
418 { | |
419 ConnContext * ctx = otr_get_context(buddy); | |
420 | |
421 if (!userstate || !ctx || ctx->msgstate != OTRL_MSGSTATE_ENCRYPTED){ | |
422 scr_LogPrint(LPRINT_LOGNORM, | |
423 "You have to start an OTR channel with %s before you can " | |
424 "use SMP.", buddy); | |
425 return NULL; | |
426 } | |
427 | |
428 return ctx; | |
429 } | |
430 | |
431 void otr_smp_query(const char * buddy, const char * secret) | |
432 { | |
433 ConnContext * ctx = otr_context_encrypted(buddy); | |
434 | |
435 if (!secret) { | |
436 scr_LogPrint(LPRINT_LOGNORM, | |
437 "Using SMP without a secret isn't a good idea."); | |
438 return; | |
439 } | |
440 | |
441 if (ctx) { | |
442 otrl_message_initiate_smp(userstate, &ops, NULL, ctx, secret, | |
443 strlen(secret)); | |
444 scr_WriteIncomingMessage(ctx->username, | |
445 "OTR: Socialist Millionaires' Protocol " | |
446 "initiated.", 0, HBB_PREFIX_INFO); | |
447 } | |
448 } | |
449 | |
450 void otr_smp_respond(const char * buddy, const char * secret) | |
451 { | |
452 ConnContext * ctx = otr_context_encrypted(buddy); | |
453 | |
454 if (!secret) { | |
455 scr_LogPrint(LPRINT_LOGNORM, | |
456 "Using SMP without a secret isn't a good idea."); | |
457 return; | |
458 } | |
459 | |
460 if (ctx) { | |
461 if (!ctx->smstate->secret) { | |
462 scr_LogPrint(LPRINT_LOGNORM, | |
463 "Don't call smpr before you haven't received an SMP " | |
464 "Initiation!"); | |
465 return; | |
466 } | |
467 otrl_message_respond_smp(userstate, &ops, NULL, ctx, secret, | |
468 strlen(secret)); | |
469 scr_WriteIncomingMessage(ctx->username, | |
470 "OTR: Socialist Millionaires' Protocol: " | |
471 "response sent", 0, HBB_PREFIX_INFO); | |
472 } | |
473 } | |
474 | |
475 void otr_smp_abort(const char * buddy) | |
476 { | |
477 ConnContext * ctx = otr_context_encrypted(buddy); | |
478 | |
479 if (ctx) { | |
480 otrl_message_abort_smp(userstate, &ops, NULL, ctx); | |
481 scr_WriteIncomingMessage(ctx->username, | |
482 "OTR: Socialist Millionaires' Protocol aborted.", | |
483 0, HBB_PREFIX_INFO); | |
484 } | |
485 } | |
486 | |
487 void otr_key(void) | |
488 { | |
489 OtrlPrivKey * key; | |
490 char readable[45] = ""; | |
491 | |
492 if(!userstate) | |
493 return; | |
494 for (key = userstate->privkey_root; key; key = key->next) { | |
495 otrl_privkey_fingerprint(userstate, readable, key->accountname, | |
496 key->protocol); | |
497 scr_LogPrint(LPRINT_LOGNORM, "%s: %s", key->accountname, readable); | |
498 } | |
499 } | |
500 | |
501 /* Return the OTR policy for the given context. */ | |
502 static OtrlPolicy cb_policy(void *opdata, ConnContext *ctx) | |
503 { | |
504 enum otr_policy p = settings_otr_getpolicy(NULL); | |
505 | |
506 if(ctx) | |
507 if(settings_otr_getpolicy(ctx->username)) | |
508 p = settings_otr_getpolicy(ctx->username); | |
509 | |
510 switch (p) { | |
511 case plain: | |
512 return OTRL_POLICY_NEVER; | |
513 case opportunistic: | |
514 return OTRL_POLICY_OPPORTUNISTIC & ~OTRL_POLICY_ALLOW_V1; | |
515 case manual: | |
516 return OTRL_POLICY_MANUAL & ~OTRL_POLICY_ALLOW_V1; | |
517 case always: | |
518 return OTRL_POLICY_ALWAYS & ~OTRL_POLICY_ALLOW_V1; | |
519 } | |
520 } | |
521 | |
522 /* Create a private key for the given accountname/protocol if | |
523 * desired. */ | |
524 static void cb_create_privkey(void *opdata, const char *accountname, | |
525 const char *protocol) | |
526 { | |
527 gcry_error_t e; | |
528 | |
529 scr_LogPrint(LPRINT_LOGNORM, | |
530 "Generating new OTR key for %s. This may take a while...", | |
531 accountname); | |
532 scr_DoUpdate(); | |
533 | |
534 e = otrl_privkey_generate(userstate, keyfile, accountname, protocol); | |
535 | |
536 if (e) | |
537 scr_LogPrint(LPRINT_LOGNORM, "OTR key generation failed!" | |
538 " Please mkdir ~/.mcabber/otr/ and restart mcabber."); | |
539 else | |
540 scr_LogPrint(LPRINT_LOGNORM, "OTR key generated."); | |
541 } | |
542 | |
543 /* Report whether you think the given user is online. Return 1 if | |
544 * 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. */ | |
548 static int cb_is_logged_in(void *opdata, const char *accountname, | |
549 const char *protocol, const char *recipient) | |
550 { | |
551 int ret = (roster_getstatus((char *)recipient, NULL) != offline); | |
552 return ret; | |
553 } | |
554 | |
555 /* Send the given IM to the given recipient from the given | |
556 * accountname/protocol. */ | |
557 static void cb_inject_message(void *opdata, const char *accountname, | |
558 const char *protocol, const char *recipient, | |
559 const char *message) | |
560 { | |
561 char * id = g_strdup("otrinject"); | |
562 jb_send_msg(recipient, message, ROSTER_TYPE_USER, "", id, NULL); | |
563 g_free(id); | |
564 } | |
565 | |
566 /* Display a notification message for a particular | |
567 * accountname / protocol / username conversation. */ | |
568 static void cb_notify(void *opdata, OtrlNotifyLevel level, | |
569 const char *accountname, const char *protocol, | |
570 const char *username, const char *title, | |
571 const char *primary, const char *secondary) | |
572 { | |
573 char * type; | |
574 char *sbuf = NULL; | |
575 switch (level) { | |
576 case OTRL_NOTIFY_ERROR: type = "error"; break; | |
577 case OTRL_NOTIFY_WARNING: type = "warning"; break; | |
578 case OTRL_NOTIFY_INFO: type = "info"; break; | |
579 } | |
580 sbuf = g_strdup_printf("OTR %s:%s\n%s\n%s",type,title, primary, secondary); | |
581 scr_WriteIncomingMessage(username, sbuf, 0, HBB_PREFIX_INFO); | |
582 g_free(sbuf); | |
583 } | |
584 | |
585 /* Display an OTR control message for a particular | |
586 * accountname / protocol / username conversation. Return 0 if you are able | |
587 * to successfully display it. If you return non-0 (or if this | |
588 * function is NULL), the control message will be displayed inline, | |
589 * as a received message, or else by using the above notify() | |
590 * callback. */ | |
591 static int cb_display_otr_message(void *opdata, const char *accountname, | |
592 const char *protocol, const char *username, | |
593 const char *msg) | |
594 { | |
595 scr_WriteIncomingMessage(username, msg, 0, HBB_PREFIX_INFO); | |
596 return 0; | |
597 } | |
598 | |
599 /* When the list of ConnContexts changes (including a change in | |
600 * state), this is called so the UI can be updated. */ | |
601 static void cb_update_context_list(void *opdata) | |
602 { | |
603 /*maybe introduce new status characters for mcabber, | |
604 * then use this function (?!)*/ | |
605 } | |
606 | |
607 /* Return a newly allocated string containing a human-friendly name | |
608 * for the given protocol id */ | |
609 static const char *cb_protocol_name(void *opdata, const char *protocol) | |
610 { | |
611 return protocol; | |
612 } | |
613 | |
614 /* Deallocate a string allocated by protocol_name */ | |
615 static void cb_protocol_name_free (void *opdata, const char *protocol_name) | |
616 { | |
617 /* We didn't allocated memory, so we don't have to free anything :p */ | |
618 } | |
619 | |
620 /* A new fingerprint for the given user has been received. */ | |
621 static void cb_new_fingerprint(void *opdata, OtrlUserState us, | |
622 const char *accountname, const char *protocol, | |
623 const char *username, | |
624 unsigned char fingerprint[20]) | |
625 { | |
626 char *sbuf = NULL; | |
627 char readable[45]; | |
628 | |
629 otrl_privkey_hash_to_human(readable, fingerprint); | |
630 sbuf = g_strdup_printf("OTR: new fingerprint: %s", readable); | |
631 scr_WriteIncomingMessage(username, sbuf, 0, HBB_PREFIX_INFO); | |
632 g_free(sbuf); | |
633 } | |
634 | |
635 /* The list of known fingerprints has changed. Write them to disk. */ | |
636 static void cb_write_fingerprints(void *opdata) | |
637 { | |
638 otrl_privkey_write_fingerprints(userstate, fprfile); | |
639 } | |
640 | |
641 /* A ConnContext has entered a secure state. */ | |
642 static void cb_gone_secure(void *opdata, ConnContext *context) | |
643 { | |
644 scr_WriteIncomingMessage(context->username, "OTR: channel established", 0, | |
645 HBB_PREFIX_INFO); | |
646 } | |
647 | |
648 /* A ConnContext has left a secure state. */ | |
649 static void cb_gone_insecure(void *opdata, ConnContext *context) | |
650 { | |
651 scr_WriteIncomingMessage(context->username, "OTR: channel closed", 0, | |
652 HBB_PREFIX_INFO); | |
653 } | |
654 | |
655 /* We have completed an authentication, using the D-H keys we | |
656 * already knew. is_reply indicates whether we initiated the AKE. */ | |
657 static void cb_still_secure(void *opdata, ConnContext *context, int is_reply) | |
658 { | |
659 scr_WriteIncomingMessage(context->username, "OTR: channel reestablished", 0, | |
660 HBB_PREFIX_INFO); | |
661 } | |
662 | |
663 /* Log a message. The passed message will end in "\n". */ | |
664 static void cb_log_message(void *opdata, const char *message) | |
665 { | |
666 scr_LogPrint(LPRINT_DEBUG, "OTR: %s", message); | |
667 } | |
668 | |
669 /* Find the maximum message size supported by this protocol. */ | |
670 static int cb_max_message_size(void *opdata, ConnContext *context) | |
671 { | |
672 return 8192; | |
673 } | |
674 | |
675 #endif /* HAVE_LIBOTR */ | |
676 /* vim: set expandtab cindent cinoptions=>2\:2(0: For Vim users... */ |