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