~ubuntu-branches/ubuntu/saucy/irssi-plugin-otr/saucy-proposed

« back to all changes in this revision

Viewing changes to otr_util.c

  • Committer: Bazaar Package Importer
  • Author(s): David Spreen
  • Date: 2009-02-16 16:33:28 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20090216163328-huzenu0s2j3uvlk3
Tags: 0.3-1
* New upstream release.
* First upload to unstable after 0.2. Introduces xchat-otr
  to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Off-the-Record Messaging (OTR) module for the irssi IRC client
 
3
 * Copyright (C) 2008  Uli Meis <a.sporto+bee@gmail.com>
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA
 
18
 */
 
19
 
 
20
#include "otr.h"
 
21
 
 
22
#include <gcrypt.h>
 
23
 
 
24
OtrlUserState otr_state = NULL;
 
25
extern OtrlMessageAppOps otr_ops;
 
26
static int otrinited = FALSE;
 
27
GSList *plistunknown = NULL;
 
28
GSList *plistknown = NULL;
 
29
 
 
30
#ifdef HAVE_GREGEX_H
 
31
GRegex *regex_policies;
 
32
#endif
 
33
 
 
34
/*
 
35
 * init otr lib.
 
36
 */
 
37
int otrlib_init()
 
38
{
 
39
 
 
40
        if (!otrinited) {
 
41
                OTRL_INIT;
 
42
                otrinited = TRUE;
 
43
        }
 
44
 
 
45
        otr_state = otrl_userstate_create();
 
46
 
 
47
        /* load keys and fingerprints */
 
48
 
 
49
        key_load();
 
50
        fps_load();
 
51
 
 
52
        otr_initops();
 
53
 
 
54
#ifdef HAVE_GREGEX_H
 
55
        regex_policies = 
 
56
                g_regex_new("([^,]+) (never|manual|handlews|opportunistic|always)"
 
57
                            "(,|$)",0,0,NULL);
 
58
#endif
 
59
 
 
60
        return otr_state==NULL;
 
61
}
 
62
 
 
63
/*
 
64
 * deinit otr lib.
 
65
 */
 
66
void otrlib_deinit()
 
67
{
 
68
        if (otr_state) {
 
69
                otr_writefps();
 
70
                otrl_userstate_free(otr_state);
 
71
                otr_state = NULL;
 
72
        }
 
73
 
 
74
        keygen_abort(TRUE);
 
75
 
 
76
        otr_setpolicies("",FALSE);
 
77
        otr_setpolicies("",TRUE);
 
78
 
 
79
#ifdef HAVE_GREGEX_H
 
80
        g_regex_unref(regex_policies);
 
81
#endif
 
82
 
 
83
}
 
84
 
 
85
 
 
86
/*
 
87
 * Free our app data.
 
88
 */
 
89
void context_free_app_info(void *data)
 
90
{
 
91
        struct co_info *coi = data;
 
92
        if (coi->msgqueue) {
 
93
                g_free(coi->msgqueue);
 
94
        }
 
95
        if (coi->ircctx)
 
96
                IRCCTX_FREE(coi->ircctx);
 
97
}
 
98
 
 
99
/*
 
100
 * Add app data to context.
 
101
 * See struct co_info for details.
 
102
 */
 
103
void context_add_app_info(void *data,ConnContext *co)
 
104
{
 
105
        IRC_CTX *ircctx = IRCCTX_DUP(data);
 
106
        struct co_info *coi = g_malloc(sizeof(struct co_info));
 
107
 
 
108
        memset(coi,0,sizeof(struct co_info));
 
109
        co->app_data = coi;
 
110
        co->app_data_free = context_free_app_info;
 
111
 
 
112
        coi->ircctx = ircctx;
 
113
        sprintf(coi->better_msg_two,formats[TXT_OTR_BETTER_TWO].def,co->accountname);
 
114
}
 
115
 
 
116
/*
 
117
 * Get a context from a pair.
 
118
 */
 
119
ConnContext *otr_getcontext(const char *accname,const char *nick,
 
120
                            int create,void *data)
 
121
{
 
122
        ConnContext *co = otrl_context_find(
 
123
                otr_state,
 
124
                nick,
 
125
                accname,
 
126
                PROTOCOLID,
 
127
                create,
 
128
                NULL,
 
129
                context_add_app_info,
 
130
                data);
 
131
 
 
132
        /* context came from a fingerprint */
 
133
        if (co&&data&&!co->app_data)
 
134
                context_add_app_info(data,co);
 
135
 
 
136
        return co;
 
137
}
 
138
 
 
139
/*
 
140
 * Hand the given message to OTR.
 
141
 * Returns NULL if OTR handled the message and 
 
142
 * the original message otherwise.
 
143
 */
 
144
char *otr_send(IRC_CTX *ircctx, const char *msg,const char *to)
 
145
{
 
146
        const char *nick = IRCCTX_NICK(ircctx);
 
147
        const char *address = IRCCTX_ADDR(ircctx);
 
148
        gcry_error_t err;
 
149
        char *newmessage = NULL;
 
150
        ConnContext *co;
 
151
        char accname[256];
 
152
 
 
153
        sprintf(accname, "%s@%s", nick, address);
 
154
 
 
155
        err = otrl_message_sending(
 
156
                otr_state, 
 
157
                &otr_ops, 
 
158
                ircctx, 
 
159
                accname,
 
160
                PROTOCOLID, 
 
161
                to, 
 
162
                msg, 
 
163
                NULL, 
 
164
                &newmessage, 
 
165
                context_add_app_info, 
 
166
                ircctx);
 
167
 
 
168
        if (err != 0) {
 
169
                otr_notice(ircctx,to,TXT_SEND_FAILED,msg);
 
170
                return NULL;
 
171
        }
 
172
 
 
173
        if (newmessage==NULL)
 
174
                return (char*)msg;
 
175
 
 
176
        /* OTR message. Need to do fragmentation */
 
177
 
 
178
        if (!(co = otr_getcontext(accname,to,FALSE,ircctx))) {
 
179
                otr_notice(ircctx,to,TXT_SEND_CHANGE);
 
180
                return NULL;
 
181
        }
 
182
 
 
183
        err = otrl_message_fragment_and_send(
 
184
                &otr_ops, 
 
185
                ircctx, 
 
186
                co,
 
187
                newmessage, 
 
188
                OTRL_FRAGMENT_SEND_ALL, 
 
189
                NULL);
 
190
 
 
191
        if (err != 0) {
 
192
                otr_notice(ircctx,to,TXT_SEND_FRAGMENT,msg);
 
193
        } else
 
194
                otr_debug(ircctx,to,TXT_SEND_CONVERTED,newmessage);
 
195
 
 
196
        return NULL;
 
197
}
 
198
 
 
199
struct ctxlist_ *otr_contexts() {
 
200
        ConnContext *context;
 
201
        Fingerprint *fprint;
 
202
        struct ctxlist_ *ctxlist = NULL, *ctxhead = NULL;
 
203
        struct fplist_ *fplist,*fphead;
 
204
        char fp[41];
 
205
        char *trust;
 
206
        int i;
 
207
 
 
208
        for(context = otr_state->context_root; context; 
 
209
            context = context->next) {
 
210
                if (!ctxlist)
 
211
                        ctxhead = ctxlist = g_malloc0(sizeof(struct ctxlist_));
 
212
                else
 
213
                        ctxlist = ctxlist->next = g_malloc0(sizeof(struct
 
214
                                                                  ctxlist_));
 
215
                switch (context->msgstate) {
 
216
                case OTRL_MSGSTATE_PLAINTEXT: ctxlist->state = STUNENCRYPTED;break;
 
217
                case OTRL_MSGSTATE_ENCRYPTED: ctxlist->state = STENCRYPTED;break;
 
218
                case OTRL_MSGSTATE_FINISHED: ctxlist->state = STFINISHED;break;
 
219
                default: ctxlist->state = STUNKNOWN;break;
 
220
                }
 
221
                ctxlist->username = context->username;
 
222
                ctxlist->accountname = context->accountname;
 
223
 
 
224
                fplist = fphead = NULL;
 
225
                for (fprint = context->fingerprint_root.next; fprint;
 
226
                     fprint = fprint->next) {
 
227
                        if (!fplist)
 
228
                                fphead = fplist = g_malloc0(sizeof(struct
 
229
                                                                   fplist_));
 
230
                        else
 
231
                                fplist = fplist->next = g_malloc0(sizeof(struct
 
232
                                                                         fplist_));
 
233
                        trust = fprint->trust ? : "";
 
234
                        for(i=0;i<20;++i)
 
235
                                sprintf(fp+i*2, "%02x",
 
236
                                             fprint->fingerprint[i]);
 
237
                        fplist->fp = g_strdup(fp);
 
238
                        if (*trust=='\0')
 
239
                                fplist->authby = NOAUTH;
 
240
                        else if (strcmp(trust,"smp")==0)
 
241
                                fplist->authby = AUTHSMP;
 
242
                        else 
 
243
                                fplist->authby = AUTHMAN;
 
244
                }
 
245
 
 
246
                ctxlist->fplist = fphead;
 
247
        }
 
248
        return ctxhead;
 
249
}
 
250
 
 
251
/*
 
252
 * Get the OTR status of this conversation.
 
253
 */
 
254
int otr_getstatus(char *mynick, char *nick, char *server)
 
255
{
 
256
        ConnContext *co;
 
257
        char accname[128];
 
258
        struct co_info *coi;
 
259
 
 
260
        sprintf(accname, "%s@%s", mynick, server);
 
261
 
 
262
        if (!(co = otr_getcontext(accname,nick,FALSE,NULL))) {
 
263
                return 0;
 
264
        }
 
265
 
 
266
        coi = co->app_data;
 
267
 
 
268
        switch (co->msgstate) {
 
269
        case OTRL_MSGSTATE_PLAINTEXT:
 
270
                return TXT_ST_PLAINTEXT;
 
271
        case OTRL_MSGSTATE_ENCRYPTED: {
 
272
                char *trust = co->active_fingerprint->trust;
 
273
                int ex = co->smstate->nextExpected;
 
274
 
 
275
                if (trust&&(*trust!='\0'))
 
276
                        return strcmp(trust,"smp")==0 ? TXT_ST_TRUST_SMP : TXT_ST_TRUST_MANUAL;
 
277
 
 
278
                switch (ex) {
 
279
                case OTRL_SMP_EXPECT1:
 
280
                        return TXT_ST_UNTRUSTED;
 
281
                case OTRL_SMP_EXPECT2:
 
282
                        return TXT_ST_SMP_WAIT_2;
 
283
                case OTRL_SMP_EXPECT3: 
 
284
                case OTRL_SMP_EXPECT4:
 
285
                        return TXT_ST_SMP_FINALIZE;
 
286
                default:
 
287
                        return TXT_ST_SMP_UNKNOWN;
 
288
                }
 
289
        }
 
290
        case OTRL_MSGSTATE_FINISHED:
 
291
                return TXT_ST_FINISHED;
 
292
        default:
 
293
                return TXT_ST_UNKNOWN;
 
294
        }
 
295
}
 
296
 
 
297
/*
 
298
 * Finish the conversation.
 
299
 */
 
300
void otr_finish(IRC_CTX *ircctx, char *nick, const char *peername, int inquery)
 
301
{
 
302
        ConnContext *co;
 
303
        char accname[128];
 
304
        struct co_info *coi;
 
305
        char *pserver = NULL;
 
306
 
 
307
        if (peername) {
 
308
                pserver = strchr(peername,'@');
 
309
                if (!pserver)
 
310
                        return;
 
311
                ircctx = server_find_address(pserver+1);
 
312
                if (!ircctx)
 
313
                        return;
 
314
                *pserver = '\0';
 
315
                nick = (char*)peername;
 
316
        }
 
317
 
 
318
        sprintf((char*)accname, "%s@%s", IRCCTX_NICK(ircctx), IRCCTX_ADDR(ircctx));
 
319
 
 
320
        if (!(co = otr_getcontext(accname,nick,FALSE,NULL))) {
 
321
                if (inquery)
 
322
                        otr_noticest(TXT_CTX_NOT_FOUND,
 
323
                                     accname,nick);
 
324
                if (peername)
 
325
                        *pserver = '@';
 
326
                return;
 
327
        }
 
328
 
 
329
        otrl_message_disconnect(otr_state,&otr_ops,ircctx,accname,
 
330
                                PROTOCOLID,nick);
 
331
 
 
332
        if (inquery) {
 
333
                otr_info(ircctx,nick,TXT_CMD_FINISH,nick,IRCCTX_ADDR(ircctx));
 
334
        } else {
 
335
                otr_infost(TXT_CMD_FINISH,nick,IRCCTX_ADDR(ircctx));
 
336
        }
 
337
 
 
338
        coi = co->app_data;
 
339
 
 
340
        /* finish if /otr finish has been issued. Reset if
 
341
         * we're called cause the query window has been closed. */
 
342
        if (coi) 
 
343
                coi->finished = inquery;
 
344
 
 
345
        if (peername)
 
346
                *pserver = '@';
 
347
}
 
348
 
 
349
void otr_finishall()
 
350
{
 
351
        ConnContext *context;
 
352
        int finished=0;
 
353
 
 
354
        for(context = otr_state->context_root; context; 
 
355
            context = context->next) {
 
356
                struct co_info *coi = context->app_data;
 
357
 
 
358
                if (context->msgstate!=OTRL_MSGSTATE_ENCRYPTED)
 
359
                        continue;
 
360
 
 
361
                otrl_message_disconnect(otr_state,&otr_ops,coi->ircctx,
 
362
                                        context->accountname,
 
363
                                        PROTOCOLID,
 
364
                                        context->username);
 
365
 
 
366
                otr_infost(TXT_CMD_FINISH,context->username,
 
367
                           IRCCTX_ADDR(coi->ircctx));
 
368
                finished++;
 
369
        }
 
370
 
 
371
        if (!finished)
 
372
                otr_infost(TXT_CMD_FINISHALL_NONE);
 
373
}
 
374
 
 
375
/*
 
376
 * Trust our peer.
 
377
 */
 
378
void otr_trust(IRC_CTX *ircctx, char *nick, const char *peername)
 
379
{
 
380
        ConnContext *co;
 
381
        char accname[128];
 
382
        struct co_info *coi;
 
383
        char *pserver = NULL;
 
384
 
 
385
        if (peername) {
 
386
                pserver = strchr(peername,'@');
 
387
                if (!pserver)
 
388
                        return;
 
389
                ircctx = server_find_address(pserver+1);
 
390
                if (!ircctx)
 
391
                        return;
 
392
                *pserver = '\0';
 
393
                nick = (char*)peername;
 
394
        }
 
395
 
 
396
        sprintf((char*)accname, "%s@%s", IRCCTX_NICK(ircctx), IRCCTX_ADDR(ircctx));
 
397
 
 
398
        if (!(co = otr_getcontext(accname,nick,FALSE,NULL))) {
 
399
                otr_noticest(TXT_CTX_NOT_FOUND,
 
400
                             accname,nick);
 
401
                if (peername)
 
402
                        *pserver = '@';
 
403
                return;
 
404
        }
 
405
 
 
406
        otrl_context_set_trust(co->active_fingerprint,"manual");
 
407
 
 
408
        coi = co->app_data;
 
409
        coi->smp_failed = FALSE;
 
410
 
 
411
        otr_notice(ircctx,nick,TXT_FP_TRUST,nick);
 
412
 
 
413
        if (peername)
 
414
                *pserver = '@';
 
415
}
 
416
 
 
417
/*
 
418
 * Abort any ongoing SMP authentication.
 
419
 */
 
420
void otr_abort_auth(ConnContext *co, IRC_CTX *ircctx, const char *nick)
 
421
{
 
422
        struct co_info *coi;
 
423
 
 
424
        coi = co->app_data;
 
425
 
 
426
        coi->received_smp_init = FALSE;
 
427
 
 
428
        otr_notice(ircctx,nick,
 
429
                   co->smstate->nextExpected!=OTRL_SMP_EXPECT1 ? 
 
430
                   TXT_AUTH_ABORTED_ONGOING :
 
431
                   TXT_AUTH_ABORTED);
 
432
 
 
433
        otrl_message_abort_smp(otr_state,&otr_ops,ircctx,co);
 
434
}
 
435
 
 
436
/*
 
437
 * implements /otr authabort
 
438
 */
 
439
void otr_authabort(IRC_CTX *ircctx, char *nick, const char *peername)
 
440
{
 
441
        ConnContext *co;
 
442
        char accname[128];
 
443
        char *pserver = NULL;
 
444
 
 
445
        if (peername) {
 
446
                pserver = strchr(peername,'@');
 
447
                if (!pserver)
 
448
                        return;
 
449
                ircctx = server_find_address(pserver+1);
 
450
                if (!ircctx)
 
451
                        return;
 
452
                *pserver = '\0';
 
453
                nick = (char*)peername;
 
454
        }
 
455
 
 
456
        sprintf((char*)accname, "%s@%s", IRCCTX_NICK(ircctx), IRCCTX_ADDR(ircctx));
 
457
 
 
458
        if (!(co = otr_getcontext(accname,nick,FALSE,NULL))) {
 
459
                otr_noticest(TXT_CTX_NOT_FOUND,
 
460
                             accname,nick);
 
461
                if (peername)
 
462
                        *pserver = '@';
 
463
                return;
 
464
        }
 
465
 
 
466
        otr_abort_auth(co,ircctx,nick);
 
467
 
 
468
        if (peername)
 
469
                *pserver = '@';
 
470
}
 
471
 
 
472
/*
 
473
 * Initiate or respond to SMP authentication.
 
474
 */
 
475
void otr_auth(IRC_CTX *ircctx, char *nick, const char *peername, const char *secret)
 
476
{
 
477
        ConnContext *co;
 
478
        char accname[128];
 
479
        struct co_info *coi;
 
480
        char *pserver = NULL;
 
481
 
 
482
        if (peername) {
 
483
                pserver = strchr(peername,'@');
 
484
                if (!pserver)
 
485
                        return;
 
486
                ircctx = server_find_address(pserver+1);
 
487
                if (!ircctx)
 
488
                        return;
 
489
                *pserver = '\0';
 
490
                nick = (char*)peername;
 
491
        }
 
492
 
 
493
        sprintf((char*)accname, "%s@%s", IRCCTX_NICK(ircctx), IRCCTX_ADDR(ircctx));
 
494
 
 
495
        if (!(co = otr_getcontext(accname,nick,FALSE,NULL))) {
 
496
                otr_noticest(TXT_CTX_NOT_FOUND,
 
497
                             accname,nick);
 
498
                if (peername)
 
499
                        *pserver = '@';
 
500
                return;
 
501
        }
 
502
 
 
503
        if (co->msgstate!=OTRL_MSGSTATE_ENCRYPTED) {
 
504
                otr_notice(ircctx,nick,TXT_AUTH_NEEDENC);
 
505
                return;
 
506
        }
 
507
 
 
508
        coi = co->app_data;
 
509
 
 
510
        /* Aborting an ongoing auth */
 
511
        if (co->smstate->nextExpected!=OTRL_SMP_EXPECT1)
 
512
                otr_abort_auth(co,ircctx,nick);
 
513
 
 
514
        coi->smp_failed = FALSE;
 
515
 
 
516
        /* reset trust level */
 
517
        if (co->active_fingerprint) {
 
518
                char *trust = co->active_fingerprint->trust;
 
519
                if (trust&&(*trust!='\0')) {
 
520
                        otrl_context_set_trust(co->active_fingerprint, "");
 
521
                        otr_writefps();
 
522
                }
 
523
        }
 
524
 
 
525
        if (!coi->received_smp_init)
 
526
                otrl_message_initiate_smp(
 
527
                        otr_state, 
 
528
                        &otr_ops,
 
529
                        ircctx,
 
530
                        co,
 
531
                        (unsigned char*)secret,
 
532
                        strlen(secret));
 
533
        else
 
534
                otrl_message_respond_smp(
 
535
                        otr_state,
 
536
                        &otr_ops,
 
537
                        ircctx,
 
538
                        co,
 
539
                        (unsigned char*)secret,
 
540
                        strlen(secret));
 
541
 
 
542
        otr_notice(ircctx,nick,
 
543
                   coi->received_smp_init ?
 
544
                   TXT_AUTH_RESPONDING :
 
545
                   TXT_AUTH_INITIATED);
 
546
 
 
547
        statusbar_items_redraw("otr");
 
548
 
 
549
        if (peername)
 
550
                *pserver = '@';
 
551
}
 
552
 
 
553
/* 
 
554
 * Handles incoming TLVs of the SMP authentication type. We're not only updating
 
555
 * our own state but also giving libotr a leg up so it gets through the auth.
 
556
 */
 
557
void otr_handle_tlvs(OtrlTLV *tlvs, ConnContext *co, 
 
558
                     struct co_info *coi, 
 
559
                     IRC_CTX *ircctx, const char *from) 
 
560
{
 
561
        int abort = FALSE;
 
562
 
 
563
        OtrlTLV *tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1);
 
564
        if (tlv) {
 
565
                if (co->smstate->nextExpected != OTRL_SMP_EXPECT1) {
 
566
                        otr_notice(ircctx,from,TXT_AUTH_HAVE_OLD,
 
567
                                   from);
 
568
                        abort = TRUE;
 
569
                } else {
 
570
                        otr_notice(ircctx,from,TXT_AUTH_PEER,
 
571
                                   from);
 
572
                        coi->received_smp_init = TRUE;
 
573
                }
 
574
        }
 
575
 
 
576
        tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2);
 
577
        if (tlv) {
 
578
                if (co->smstate->nextExpected != OTRL_SMP_EXPECT2) {
 
579
                        otr_notice(ircctx,from,
 
580
                                   TXT_AUTH_PEER_REPLY_WRONG,
 
581
                                   from);
 
582
                        abort = TRUE;
 
583
                } else {
 
584
                        otr_notice(ircctx,from,
 
585
                                   TXT_AUTH_PEER_REPLIED,
 
586
                                   from);
 
587
                        co->smstate->nextExpected = OTRL_SMP_EXPECT4;
 
588
                }
 
589
        }
 
590
 
 
591
        tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3);
 
592
        if (tlv) {
 
593
                if (co->smstate->nextExpected != OTRL_SMP_EXPECT3) {
 
594
                        otr_notice(ircctx,from,
 
595
                                   TXT_AUTH_PEER_WRONG_SMP3,
 
596
                                   from);
 
597
                        abort = TRUE;
 
598
                } else {
 
599
                        char *trust = co->active_fingerprint->trust;
 
600
                        if (trust&&(*trust!='\0')) {
 
601
                                otr_notice(ircctx,from,
 
602
                                           TXT_AUTH_SUCCESSFUL);
 
603
                        } else {
 
604
                                otr_notice(ircctx,from,
 
605
                                           TXT_AUTH_FAILED);
 
606
                                coi->smp_failed = TRUE;
 
607
                        }
 
608
                        co->smstate->nextExpected = OTRL_SMP_EXPECT1;
 
609
                        coi->received_smp_init = FALSE;
 
610
                }
 
611
        }
 
612
 
 
613
        tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4);
 
614
        if (tlv) {
 
615
                if (co->smstate->nextExpected != OTRL_SMP_EXPECT4) {
 
616
                        otr_notice(ircctx,from,
 
617
                                   TXT_AUTH_PEER_WRONG_SMP4,
 
618
                                   from);
 
619
                        abort = TRUE;
 
620
                } else {
 
621
                        char *trust = co->active_fingerprint->trust;
 
622
                        if (trust&&(*trust!='\0')) {
 
623
                                otr_notice(ircctx,from,
 
624
                                           TXT_AUTH_SUCCESSFUL);
 
625
                        } else {
 
626
                                /* unreachable since 4 is never sent out on
 
627
                                 * error */
 
628
                                otr_notice(ircctx,from,
 
629
                                           TXT_AUTH_FAILED);
 
630
                                coi->smp_failed = TRUE;
 
631
                        }
 
632
                        co->smstate->nextExpected = OTRL_SMP_EXPECT1;
 
633
                        coi->received_smp_init = FALSE;
 
634
                }
 
635
        }
 
636
        if (abort)
 
637
                otr_abort_auth(co,ircctx,from);
 
638
 
 
639
        tlv = otrl_tlv_find(tlvs, OTRL_TLV_DISCONNECTED);
 
640
        if (tlv)
 
641
                otr_notice(ircctx,from,TXT_PEER_FINISHED,from);
 
642
 
 
643
        statusbar_items_redraw("otr");
 
644
}
 
645
 
 
646
/*
 
647
 * Hand the given message to OTR.
 
648
 * Returns NULL if its an OTR protocol message and 
 
649
 * the (possibly) decrypted message otherwise.
 
650
 */
 
651
char *otr_receive(IRC_CTX *ircctx, const char *msg,const char *from)
 
652
{
 
653
        int ignore_message;
 
654
        char *newmessage = NULL;
 
655
        char accname[256];
 
656
        char *lastmsg;
 
657
        ConnContext *co;
 
658
        struct co_info *coi;
 
659
        OtrlTLV *tlvs;
 
660
 
 
661
        sprintf(accname, "%s@%s", IRCCTX_NICK(ircctx), IRCCTX_ADDR(ircctx));
 
662
 
 
663
        if (!(co = otr_getcontext(accname,from,TRUE,ircctx))) {
 
664
                otr_noticest(TXT_CTX_NOT_CREATE,
 
665
                             accname,from);
 
666
                return NULL;
 
667
        }
 
668
 
 
669
        coi = co->app_data;
 
670
 
 
671
        /* Really lame but I don't see how you could do this in a generic
 
672
         * way unless the IRC server would somehow mark continuation messages.
 
673
         */
 
674
        if ((strcmp(msg,coi->better_msg_two)==0)||
 
675
            (strcmp(msg,formats[TXT_OTR_BETTER_THREE].def)==0)) {
 
676
                otr_debug(ircctx,from,TXT_RECEIVE_IGNORE_QUERY);
 
677
                return NULL;
 
678
        }
 
679
 
 
680
        /* The server might have split lines that were too long 
 
681
         * (bitlbee does that). The heuristic is simple: If we can find ?OTR:
 
682
         * in the message but it doesn't end with a ".", queue it and wait
 
683
         * for the rest.
 
684
         */
 
685
        lastmsg = co->app_data;
 
686
 
 
687
        if (coi->msgqueue) { /* already something in the queue */
 
688
                strcpy(coi->msgqueue+strlen(coi->msgqueue),msg);
 
689
 
 
690
                /* wait for more? */
 
691
                if ((strlen(msg)>OTR_MAX_MSG_SIZE)&&
 
692
                    (msg[strlen(msg)-1]!='.')&&
 
693
                    (msg[strlen(msg)-1]!=','))
 
694
                        return NULL;
 
695
 
 
696
                otr_debug(ircctx,from,TXT_RECEIVE_DEQUEUED,
 
697
                          strlen(coi->msgqueue));
 
698
 
 
699
                msg = coi->msgqueue;
 
700
                coi->msgqueue = NULL;
 
701
 
 
702
                /* this is freed thru our caller by otrl_message_free.
 
703
                 * Currently ok since that just uses free().
 
704
                 */
 
705
 
 
706
        } else if (strstr(msg,"?OTR:")&&
 
707
                   (strlen(msg)>OTR_MAX_MSG_SIZE)&&
 
708
                   (msg[strlen(msg)-1]!='.')&&
 
709
                   (msg[strlen(msg)-1]!=',')) {
 
710
                coi->msgqueue = malloc(4096*sizeof(char));
 
711
                strcpy(coi->msgqueue,msg);
 
712
                otr_debug(ircctx,from,TXT_RECEIVE_QUEUED,strlen(msg));
 
713
                return NULL;
 
714
        }
 
715
 
 
716
        ignore_message = otrl_message_receiving(
 
717
                otr_state,
 
718
                &otr_ops,
 
719
                ircctx,
 
720
                accname, 
 
721
                PROTOCOLID, 
 
722
                from, 
 
723
                msg, 
 
724
                &newmessage,
 
725
                &tlvs,
 
726
                NULL,
 
727
                NULL);
 
728
 
 
729
        if (tlvs) 
 
730
                otr_handle_tlvs(tlvs,co,coi,ircctx,from);
 
731
        
 
732
        if (ignore_message) {
 
733
                otr_debug(ircctx,from,
 
734
                          TXT_RECEIVE_IGNORE, strlen(msg),accname,from,msg);
 
735
                return NULL;
 
736
        }
 
737
 
 
738
        if (newmessage)
 
739
                otr_debug(ircctx,from,TXT_RECEIVE_CONVERTED);
 
740
 
 
741
        return newmessage ? : (char*)msg;
 
742
}
 
743
 
 
744
void otr_setpolicies(const char *policies, int known)
 
745
{
 
746
#ifdef HAVE_GREGEX_H
 
747
        GMatchInfo *match_info;
 
748
        GSList *plist = known ? plistknown : plistunknown;
 
749
 
 
750
        if (plist) {
 
751
                GSList *p = plist;
 
752
                do {
 
753
                        struct plistentry *ple = p->data;
 
754
                        g_pattern_spec_free(ple->namepat);
 
755
                        g_free(p->data);
 
756
                } while ((p = g_slist_next(p)));
 
757
 
 
758
                g_slist_free(plist);
 
759
                plist = NULL;
 
760
        }
 
761
 
 
762
        g_regex_match(regex_policies,policies,0,&match_info);
 
763
 
 
764
        while(g_match_info_matches(match_info)) {
 
765
                struct plistentry *ple = (struct plistentry *)g_malloc0(sizeof(struct plistentry));
 
766
                char *pol = g_match_info_fetch(match_info, 2);
 
767
 
 
768
                ple->namepat = g_pattern_spec_new(g_match_info_fetch(match_info, 1));
 
769
                
 
770
                switch (*pol) {
 
771
                case 'n':
 
772
                        ple->policy = OTRL_POLICY_NEVER;
 
773
                        break;
 
774
                case 'm':
 
775
                        ple->policy = OTRL_POLICY_MANUAL;
 
776
                        break;
 
777
                case 'h':
 
778
                        ple->policy = OTRL_POLICY_MANUAL|OTRL_POLICY_WHITESPACE_START_AKE;
 
779
                        break;
 
780
                case 'o':
 
781
                        ple->policy = OTRL_POLICY_OPPORTUNISTIC;
 
782
                        break;
 
783
                case 'a':
 
784
                        ple->policy = OTRL_POLICY_ALWAYS;
 
785
                        break;
 
786
                }
 
787
 
 
788
                plist = g_slist_append(plist,ple);
 
789
 
 
790
                g_free(pol);
 
791
 
 
792
                g_match_info_next(match_info, NULL);
 
793
        }
 
794
 
 
795
        g_match_info_free(match_info);
 
796
 
 
797
        if (known)
 
798
                plistknown = plist;
 
799
        else
 
800
                plistunknown = plist;
 
801
#endif
 
802
}