~ubuntu-branches/ubuntu/vivid/pidgin-otr/vivid-proposed

« back to all changes in this revision

Viewing changes to otr-plugin.c

  • Committer: Bazaar Package Importer
  • Author(s): Thibaut VARENE
  • Date: 2008-07-10 17:34:32 UTC
  • mfrom: (2.1.2 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080710173432-aqx359odj7cp182a
Tags: 3.2.0-2
Make key generation use /dev/urandom (Closes: #489523)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 *  Off-the-Record Messaging plugin for pidgin
3
 
 *  Copyright (C) 2004-2005  Nikita Borisov and Ian Goldberg
 
3
 *  Copyright (C) 2004-2008  Ian Goldberg, Rob Smits,
 
4
 *                           Chris Alexander, Nikita Borisov
4
5
 *                           <otr@cypherpunks.ca>
5
6
 *
6
7
 *  This program is free software; you can redistribute it and/or modify
43
44
#include "gtkplugin.h"
44
45
#endif
45
46
 
 
47
#ifdef ENABLE_NLS
 
48
 
 
49
#ifdef WIN32
 
50
/* On Win32, include win32dep.h from pidgin for correct definition
 
51
 * of LOCALEDIR */
 
52
#include "win32dep.h"
 
53
#endif /* WIN32 */
 
54
 
 
55
/* internationalisation header */
 
56
#include <glib/gi18n-lib.h>
 
57
 
 
58
#endif /* ENABLE_NLS */
 
59
 
46
60
/* libotr headers */
47
61
#include <libotr/privkey.h>
48
62
#include <libotr/proto.h>
 
63
#include <libotr/tlv.h>
49
64
#include <libotr/message.h>
50
65
#include <libotr/userstate.h>
51
66
 
56
71
 
57
72
#ifdef USING_GTK
58
73
/* purple-otr GTK headers */
 
74
#include <glib.h>
59
75
#include "gtk-ui.h"
60
76
#include "gtk-dialog.h"
61
77
#endif
79
95
/* We'll only use the one OtrlUserState. */
80
96
OtrlUserState otrg_plugin_userstate = NULL;
81
97
 
 
98
/* GLib HashTable for storing the maximum message size for various
 
99
 * protocols. */
 
100
GHashTable* mms_table;
 
101
 
82
102
/* Send an IM from the given account to the given recipient.  Display an
83
103
 * error dialog if that account isn't currently logged in. */
84
104
void otrg_plugin_inject_message(PurpleAccount *account, const char *recipient,
91
111
        const char *protocol = purple_account_get_protocol_id(account);
92
112
        const char *accountname = purple_account_get_username(account);
93
113
        PurplePlugin *p = purple_find_prpl(protocol);
94
 
        char *msg = g_strdup_printf("You are not currently connected to "
95
 
                "account %s (%s).", accountname,
96
 
                (p && p->info->name) ? p->info->name : "Unknown");
 
114
        char *msg = g_strdup_printf(_("You are not currently connected to "
 
115
                "account %s (%s)."), accountname,
 
116
                (p && p->info->name) ? p->info->name : _("Unknown"));
97
117
        otrg_dialog_notify_error(accountname, protocol, recipient,
98
 
                "Not connected", msg, NULL);
 
118
                _("Not connected"), msg, NULL);
99
119
        g_free(msg);
100
120
        return;
101
121
    }
106
126
{
107
127
    PurpleAccount *account;
108
128
    OtrlPolicy policy = OTRL_POLICY_DEFAULT;
 
129
    OtrgUiPrefs prefs;
109
130
 
110
131
    if (!context) return policy;
111
132
 
112
133
    account = purple_accounts_find(context->accountname, context->protocol);
113
134
    if (!account) return policy;
114
135
 
115
 
    return otrg_ui_find_policy(account, context->username);
 
136
    otrg_ui_get_prefs(&prefs, account, context->username);
 
137
    return prefs.policy;
116
138
}
117
139
 
118
140
static const char *protocol_name_cb(void *opdata, const char *protocol)
133
155
        const char *protocol)
134
156
{
135
157
    OtrgDialogWaitHandle waithandle;
 
158
#ifndef WIN32
 
159
    mode_t mask;
 
160
#endif  /* WIN32 */
136
161
    FILE *privf;
137
162
 
138
163
    gchar *privkeyfile = g_build_filename(purple_user_dir(), PRIVKEYFNAME, NULL);
139
164
    if (!privkeyfile) {
140
 
        fprintf(stderr, "Out of memory building filenames!\n");
 
165
        fprintf(stderr, _("Out of memory building filenames!\n"));
141
166
        return;
142
167
    }
 
168
#ifndef WIN32
 
169
    mask = umask (0077);
 
170
#endif  /* WIN32 */
143
171
    privf = g_fopen(privkeyfile, "w+b");
 
172
#ifndef WIN32
 
173
    umask (mask);
 
174
#endif  /* WIN32 */
144
175
    g_free(privkeyfile);
145
176
    if (!privf) {
146
 
        fprintf(stderr, "Could not write private key file\n");
 
177
        fprintf(stderr, _("Could not write private key file\n"));
147
178
        return;
148
179
    }
149
180
 
186
217
    PurpleAccount *account = purple_accounts_find(accountname, protocol);
187
218
    if (!account) {
188
219
        PurplePlugin *p = purple_find_prpl(protocol);
189
 
        char *msg = g_strdup_printf("Unknown account %s (%s).", accountname,
190
 
                (p && p->info->name) ? p->info->name : "Unknown");
 
220
        char *msg = g_strdup_printf(_("Unknown account %s (%s)."),
 
221
                accountname,
 
222
                (p && p->info->name) ? p->info->name : _("Unknown"));
191
223
        otrg_dialog_notify_error(accountname, protocol, recipient,
192
 
                "Unknown account", msg, NULL);
 
224
                _("Unknown account"), msg, NULL);
193
225
        g_free(msg);
194
226
        return;
195
227
    }
241
273
static void write_fingerprints_cb(void *opdata)
242
274
{
243
275
    otrg_plugin_write_fingerprints();
 
276
    otrg_ui_update_keylist();
 
277
    otrg_dialog_resensitize_all();
244
278
}
245
279
 
246
280
static void gone_secure_cb(void *opdata, ConnContext *context)
265
299
    purple_debug_info("otr", message);
266
300
}
267
301
 
 
302
static int max_message_size_cb(void *opdata, ConnContext *context)
 
303
{
 
304
    void* lookup_result = g_hash_table_lookup(mms_table, context->protocol);
 
305
    if (!lookup_result)
 
306
        return 0;
 
307
    else
 
308
        return *((int*)lookup_result);
 
309
}
 
310
 
268
311
static OtrlMessageAppOps ui_ops = {
269
312
    policy_cb,
270
313
    create_privkey_cb,
280
323
    gone_secure_cb,
281
324
    gone_insecure_cb,
282
325
    still_secure_cb,
283
 
    log_message_cb
 
326
    log_message_cb,
 
327
    max_message_size_cb,
 
328
    NULL,                   /* account_name */
 
329
    NULL                    /* account_name_free */
284
330
};
285
331
 
286
 
static void process_sending_im(PurpleAccount *account, char *who, char **message,
287
 
        void *m)
 
332
static void process_sending_im(PurpleAccount *account, char *who,
 
333
        char **message, void *m)
288
334
{
289
335
    char *newmessage = NULL;
290
336
    const char *accountname = purple_account_get_username(account);
307
353
        free(*message);
308
354
        *message = ourm;
309
355
    } else if (newmessage) {
310
 
        char *ourm = malloc(strlen(newmessage) + 1);
311
 
        if (ourm) {
312
 
            strcpy(ourm, newmessage);
313
 
        }
 
356
        /* Fragment the message if necessary, and send all but the last
 
357
         * fragment over the network.  Pidgin will send the last
 
358
         * fragment for us. */
 
359
        ConnContext *context = otrl_context_find(otrg_plugin_userstate,
 
360
                username, accountname, protocol, 0, NULL, NULL, NULL);
 
361
        free(*message);
 
362
        *message = NULL;
 
363
        err = otrl_message_fragment_and_send(&ui_ops, NULL, context,
 
364
                newmessage, OTRL_FRAGMENT_SEND_ALL_BUT_LAST, message);
314
365
        otrl_message_free(newmessage);
315
 
        free(*message);
316
 
        *message = ourm;
317
366
    }
318
367
    free(username);
319
368
}
320
369
 
 
370
/* Abort the SMP protocol.  Used when malformed or unexpected messages
 
371
 * are received. */
 
372
void otrg_plugin_abort_smp(ConnContext *context)
 
373
{
 
374
    otrl_message_abort_smp(otrg_plugin_userstate, &ui_ops, NULL, context);
 
375
}
 
376
 
 
377
/* Start the Socialist Millionaires' Protocol over the current connection,
 
378
 * using the given initial secret, and optionally a question to pass to
 
379
 * the buddy. */
 
380
void otrg_plugin_start_smp(ConnContext *context, const char *question,
 
381
        const unsigned char *secret, size_t secretlen)
 
382
{
 
383
    otrl_message_initiate_smp_q(otrg_plugin_userstate, &ui_ops, NULL,
 
384
            context, question, secret, secretlen);
 
385
}
 
386
 
 
387
/* Continue the Socialist Millionaires' Protocol over the current connection,
 
388
 * using the given initial secret (ie finish step 2). */
 
389
void otrg_plugin_continue_smp(ConnContext *context,
 
390
        const unsigned char *secret, size_t secretlen)
 
391
{
 
392
    otrl_message_respond_smp(otrg_plugin_userstate, &ui_ops, NULL,
 
393
            context, secret, secretlen);
 
394
}
 
395
 
321
396
/* Send the default OTR Query message to the correspondent of the given
322
397
 * context, from the given account.  [account is actually a
323
398
 * PurpleAccount*, but it's declared here as void* so this can be passed
325
400
void otrg_plugin_send_default_query(ConnContext *context, void *vaccount)
326
401
{
327
402
    PurpleAccount *account = vaccount;
328
 
    char *msg = otrl_proto_default_query_msg(context->accountname,
329
 
            otrg_ui_find_policy(account, context->username));
 
403
    char *msg;
 
404
    OtrgUiPrefs prefs;
 
405
 
 
406
    otrg_ui_get_prefs(&prefs, account, context->username);
 
407
    msg = otrl_proto_default_query_msg(context->accountname,
 
408
            prefs.policy);
330
409
    otrg_plugin_inject_message(account, context->username,
331
410
            msg ? msg : "?OTRv2?");
332
411
    free(msg);
339
418
    PurpleAccount *account;
340
419
    const char *username, *accountname;
341
420
    char *msg;
 
421
    OtrgUiPrefs prefs;
342
422
    
343
423
    account = purple_conversation_get_account(conv);
344
424
    accountname = purple_account_get_username(account);
345
425
    username = purple_conversation_get_name(conv);
346
426
    
347
 
    msg = otrl_proto_default_query_msg(accountname,
348
 
            otrg_ui_find_policy(account, username));
 
427
    otrg_ui_get_prefs(&prefs, account, username);
 
428
    msg = otrl_proto_default_query_msg(accountname, prefs.policy);
349
429
    otrg_plugin_inject_message(account, username, msg ? msg : "?OTRv2?");
350
430
    free(msg);
351
431
}
360
440
    gboolean res;
361
441
    const char *accountname;
362
442
    const char *protocol;
 
443
    ConnContext *context;
 
444
    NextExpectedSMP nextMsg;
363
445
 
364
446
    if (!who || !*who || !message || !*message)
365
447
        return 0;
388
470
        otrg_dialog_finished(accountname, protocol, username);
389
471
        otrg_ui_update_keylist();
390
472
    }
391
 
    
 
473
 
 
474
    /* Keep track of our current progress in the Socialist Millionaires'
 
475
     * Protocol. */
 
476
    context = otrl_context_find(otrg_plugin_userstate, username,
 
477
            accountname, protocol, 0, NULL, NULL, NULL);
 
478
    if (context) {
 
479
        nextMsg = context->smstate->nextExpected;
 
480
 
 
481
        if (context->smstate->sm_prog_state == OTRL_SMP_PROG_CHEATED) {
 
482
            otrg_plugin_abort_smp(context);
 
483
            otrg_dialog_update_smp(context, 0.0);
 
484
            context->smstate->nextExpected = OTRL_SMP_EXPECT1;
 
485
            context->smstate->sm_prog_state = OTRL_SMP_PROG_OK;
 
486
        } else {
 
487
            tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1Q);
 
488
            if (tlv) {
 
489
                if (nextMsg != OTRL_SMP_EXPECT1)
 
490
                    otrg_plugin_abort_smp(context);
 
491
                else {
 
492
                    char *question = (char *)tlv->data;
 
493
                    char *eoq = memchr(question, '\0', tlv->len);
 
494
                    if (eoq) {
 
495
                        otrg_dialog_socialist_millionaires_q(context,
 
496
                                question);
 
497
                    }
 
498
                }
 
499
            }
 
500
            tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1);
 
501
            if (tlv) {
 
502
                if (nextMsg != OTRL_SMP_EXPECT1)
 
503
                    otrg_plugin_abort_smp(context);
 
504
                else {
 
505
                    otrg_dialog_socialist_millionaires(context);
 
506
                }
 
507
            }
 
508
            tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2);
 
509
            if (tlv) {
 
510
                if (nextMsg != OTRL_SMP_EXPECT2)
 
511
                    otrg_plugin_abort_smp(context);
 
512
                else {
 
513
                    otrg_dialog_update_smp(context, 0.6);
 
514
                    context->smstate->nextExpected = OTRL_SMP_EXPECT4;
 
515
                }
 
516
            }
 
517
            tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3);
 
518
            if (tlv) {
 
519
                if (nextMsg != OTRL_SMP_EXPECT3)
 
520
                    otrg_plugin_abort_smp(context);
 
521
                else {
 
522
                    otrg_dialog_update_smp(context, 1.0);
 
523
                    context->smstate->nextExpected = OTRL_SMP_EXPECT1;
 
524
                }
 
525
            }
 
526
            tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4);
 
527
            if (tlv) {
 
528
                if (nextMsg != OTRL_SMP_EXPECT4)
 
529
                    otrg_plugin_abort_smp(context);
 
530
                else {
 
531
                    otrg_dialog_update_smp(context, 1.0);
 
532
                    context->smstate->nextExpected = OTRL_SMP_EXPECT1;
 
533
                }
 
534
            }
 
535
            tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP_ABORT);
 
536
            if (tlv) {
 
537
                otrg_dialog_update_smp(context, 0.0);
 
538
                context->smstate->nextExpected = OTRL_SMP_EXPECT1;
 
539
            }
 
540
        }
 
541
    }
 
542
 
392
543
    otrl_tlv_free(tlvs);
393
544
 
394
545
    free(username);
409
560
    if (conv) otrg_dialog_new_conv(conv);
410
561
}
411
562
 
 
563
static void process_conv_updated(PurpleConversation *conv,
 
564
        PurpleConvUpdateType type, void *data)
 
565
{
 
566
    /* See if someone's trying to turn logging on for this conversation,
 
567
     * and we don't want them to. */
 
568
    if (type == PURPLE_CONV_UPDATE_LOGGING) {
 
569
        ConnContext *context;
 
570
        OtrgUiPrefs prefs;
 
571
        PurpleAccount *account = purple_conversation_get_account(conv);
 
572
        otrg_ui_get_prefs(&prefs, account, purple_conversation_get_name(conv));
 
573
 
 
574
        context = otrg_plugin_conv_to_context(conv);
 
575
        if (context && prefs.avoid_logging_otr &&
 
576
                context->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
 
577
                conv->logging == TRUE) {
 
578
            purple_conversation_set_logging(conv, FALSE);
 
579
        }
 
580
    }
 
581
}
 
582
 
412
583
static void process_connection_change(PurpleConnection *conn, void *data)
413
584
{
414
585
    /* If we log in or out of a connection, make sure all of the OTR
441
612
    proto = purple_account_get_protocol_id(acct);
442
613
    if (!otrg_plugin_proto_supports_otr(proto)) return;
443
614
 
444
 
    act = purple_menu_action_new("OTR Settings", (PurpleCallback)otr_options_cb,
445
 
            NULL, NULL);
 
615
    act = purple_menu_action_new(_("OTR Settings"),
 
616
            (PurpleCallback)otr_options_cb, NULL, NULL);
446
617
    *menu = g_list_append(*menu, act);
447
618
}
448
619
 
457
628
/* Write the fingerprints to disk. */
458
629
void otrg_plugin_write_fingerprints(void)
459
630
{
 
631
#ifndef WIN32
 
632
    mode_t mask;
 
633
#endif  /* WIN32 */
460
634
    FILE *storef;
461
635
    gchar *storefile = g_build_filename(purple_user_dir(), STOREFNAME, NULL);
 
636
#ifndef WIN32
 
637
    mask = umask (0077);
 
638
#endif  /* WIN32 */
462
639
    storef = g_fopen(storefile, "wb");
 
640
#ifndef WIN32
 
641
    umask (mask);
 
642
#endif  /* WIN32 */
463
643
    g_free(storefile);
464
644
    if (!storef) return;
465
645
    otrl_privkey_write_fingerprints_FILEp(otrg_plugin_userstate, storef);
487
667
    return context;
488
668
}
489
669
 
490
 
/* Find the PurpleConversation appropriate to the given ConnContext.  If
 
670
/* Find the PurpleConversation appropriate to the given userinfo.  If
491
671
 * one doesn't yet exist, create it if force_create is true. */
492
 
PurpleConversation *otrg_plugin_context_to_conv(ConnContext *context,
493
 
        int force_create)
 
672
PurpleConversation *otrg_plugin_userinfo_to_conv(const char *accountname,
 
673
        const char *protocol, const char *username, int force_create)
494
674
{
495
675
    PurpleAccount *account;
496
676
    PurpleConversation *conv;
497
677
 
498
 
    account = purple_accounts_find(context->accountname, context->protocol);
 
678
    account = purple_accounts_find(accountname, protocol);
499
679
    if (account == NULL) return NULL;
500
680
 
501
 
    conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, context->username, account);
 
681
    conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
 
682
            username, account);
502
683
    if (conv == NULL && force_create) {
503
 
        conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, context->username);
 
684
        conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, username);
504
685
    }
505
686
 
506
687
    return conv;
507
688
}
508
689
 
 
690
/* Find the PurpleConversation appropriate to the given ConnContext.  If
 
691
 * one doesn't yet exist, create it if force_create is true. */
 
692
PurpleConversation *otrg_plugin_context_to_conv(ConnContext *context,
 
693
        int force_create)
 
694
{
 
695
    return otrg_plugin_userinfo_to_conv(context->accountname,
 
696
            context->protocol, context->username, force_create);
 
697
}
 
698
 
509
699
/* What level of trust do we have in the privacy of this ConnContext? */
510
700
TrustLevel otrg_plugin_context_to_trust(ConnContext *context)
511
701
{
539
729
    }
540
730
}
541
731
 
 
732
/* Read the maxmsgsizes from a FILE* into the given GHashTable.
 
733
 * The FILE* must be open for reading. */
 
734
static void mms_read_FILEp(FILE *mmsf, GHashTable *ght)
 
735
{
 
736
    char storeline[50];
 
737
    size_t maxsize = sizeof(storeline);
 
738
 
 
739
    if (!mmsf) return;
 
740
 
 
741
    while(fgets(storeline, maxsize, mmsf)) {
 
742
        char *protocol;
 
743
        char *prot_in_table;
 
744
        char *mms;
 
745
        int *mms_in_table;
 
746
        char *tab;
 
747
        char *eol;
 
748
        /* Parse the line, which should be of the form:
 
749
         *    protocol\tmaxmsgsize\n          */
 
750
        protocol = storeline;
 
751
        tab = strchr(protocol, '\t');
 
752
        if (!tab) continue;
 
753
        *tab = '\0';
 
754
 
 
755
        mms = tab + 1;
 
756
        tab = strchr(mms, '\t');
 
757
        if (tab) continue;
 
758
        eol = strchr(mms, '\r');
 
759
        if (!eol) eol = strchr(mms, '\n');
 
760
        if (!eol) continue;
 
761
        *eol = '\0';
 
762
        
 
763
        prot_in_table = strdup(protocol);
 
764
        mms_in_table = malloc(sizeof(int));
 
765
        *mms_in_table = atoi(mms);
 
766
        g_hash_table_insert(ght, prot_in_table, mms_in_table);
 
767
    }
 
768
}
 
769
 
 
770
static void otrg_str_free(gpointer data)
 
771
{
 
772
    g_free((char*)data);
 
773
}
 
774
 
 
775
static void otrg_int_free(gpointer data)
 
776
{
 
777
    g_free((int*)data);
 
778
}
 
779
 
 
780
static void otrg_init_mms_table()
 
781
{
 
782
    /* Hardcoded defaults for maximum message sizes for various
 
783
     * protocols.  These can be overridden in the user's MAXMSGSIZEFNAME
 
784
     * file. */
 
785
    static const struct s_OtrgIdProtPair {
 
786
        char *protid;
 
787
        int maxmsgsize;
 
788
    } mmsPairs[8] = {{"prpl-msn", 1409}, {"prpl-icq", 2346},
 
789
        {"prpl-aim", 2343}, {"prpl-yahoo", 832}, {"prpl-gg", 1999},
 
790
        {"prpl-irc", 417}, {"prpl-oscar", 2343}, {NULL, 0}};
 
791
    int i = 0;
 
792
    gchar *maxmsgsizefile;
 
793
    FILE *mmsf;
 
794
 
 
795
    mms_table = g_hash_table_new_full(g_str_hash, g_str_equal,
 
796
            otrg_str_free, otrg_int_free);
 
797
 
 
798
    for (i=0; mmsPairs[i].protid != NULL; i++) {
 
799
        char* nextprot = g_strdup(mmsPairs[i].protid);
 
800
        int* nextsize = g_malloc(sizeof(int));
 
801
        *nextsize = mmsPairs[i].maxmsgsize;
 
802
        g_hash_table_insert(mms_table, nextprot, nextsize);
 
803
    }
 
804
 
 
805
    maxmsgsizefile = g_build_filename(purple_user_dir(),
 
806
            MAXMSGSIZEFNAME, NULL);
 
807
 
 
808
    if (maxmsgsizefile) {
 
809
        mmsf = g_fopen(maxmsgsizefile, "rt");
 
810
        /* Actually read the file here */
 
811
        if (mmsf) {
 
812
            mms_read_FILEp(mmsf, mms_table);
 
813
            fclose(mmsf);
 
814
        }
 
815
        g_free(maxmsgsizefile);
 
816
    }
 
817
}
 
818
 
 
819
static void otrg_free_mms_table()
 
820
{
 
821
    g_hash_table_destroy(mms_table);
 
822
}
 
823
 
542
824
static gboolean otr_plugin_load(PurplePlugin *handle)
543
825
{
544
826
    gchar *privkeyfile = g_build_filename(purple_user_dir(), PRIVKEYFNAME,
562
844
    g_free(privkeyfile);
563
845
    g_free(storefile);
564
846
 
 
847
    otrg_init_mms_table();
 
848
 
565
849
    otrg_plugin_handle = handle;
566
850
 
567
851
    /* Make our OtrlUserState; we'll only use the one. */
581
865
            PURPLE_CALLBACK(process_sending_im), NULL);
582
866
    purple_signal_connect(conv_handle, "receiving-im-msg", otrg_plugin_handle,
583
867
            PURPLE_CALLBACK(process_receiving_im), NULL);
 
868
    purple_signal_connect(conv_handle, "conversation-updated",
 
869
            otrg_plugin_handle, PURPLE_CALLBACK(process_conv_updated), NULL);
584
870
    purple_signal_connect(conv_handle, "conversation-created",
585
871
            otrg_plugin_handle, PURPLE_CALLBACK(process_conv_create), NULL);
586
872
    purple_signal_connect(conn_handle, "signed-on", otrg_plugin_handle,
590
876
    purple_signal_connect(blist_handle, "blist-node-extended-menu",
591
877
            otrg_plugin_handle, PURPLE_CALLBACK(supply_extended_menu), NULL);
592
878
 
 
879
    otrg_ui_init();
 
880
    otrg_dialog_init();
 
881
 
593
882
    purple_conversation_foreach(otrg_dialog_new_conv);
594
883
 
595
884
    return 1;
606
895
    otrl_userstate_free(otrg_plugin_userstate);
607
896
    otrg_plugin_userstate = NULL;
608
897
 
 
898
    otrg_free_mms_table();
 
899
 
609
900
    purple_signal_disconnect(core_handle, "quitting", otrg_plugin_handle,
610
901
            PURPLE_CALLBACK(process_quitting));
611
 
    purple_signal_disconnect(conv_handle, "sending-im-msg", otrg_plugin_handle,
612
 
            PURPLE_CALLBACK(process_sending_im));
613
 
    purple_signal_disconnect(conv_handle, "receiving-im-msg", otrg_plugin_handle,
614
 
            PURPLE_CALLBACK(process_receiving_im));
 
902
    purple_signal_disconnect(conv_handle, "sending-im-msg",
 
903
            otrg_plugin_handle, PURPLE_CALLBACK(process_sending_im));
 
904
    purple_signal_disconnect(conv_handle, "receiving-im-msg",
 
905
            otrg_plugin_handle, PURPLE_CALLBACK(process_receiving_im));
 
906
    purple_signal_disconnect(conv_handle, "conversation-updated",
 
907
            otrg_plugin_handle, PURPLE_CALLBACK(process_conv_updated));
615
908
    purple_signal_disconnect(conv_handle, "conversation-created",
616
909
            otrg_plugin_handle, PURPLE_CALLBACK(process_conv_create));
617
910
    purple_signal_disconnect(conn_handle, "signed-on", otrg_plugin_handle,
623
916
 
624
917
    purple_conversation_foreach(otrg_dialog_remove_conv);
625
918
 
 
919
    otrg_dialog_cleanup();
 
920
    otrg_ui_cleanup();
 
921
 
626
922
    return 1;
627
923
}
628
924
 
629
925
/* Return 1 if the given protocol supports OTR, 0 otherwise. */
630
926
int otrg_plugin_proto_supports_otr(const char *proto)
631
927
{
632
 
    /* IRC is the only protocol we know of that OTR doesn't work on (its
633
 
     * maximum message size is too small to fit a Key Exchange Message). */
634
 
    if (proto && !strcmp(proto, "prpl-irc")) {
635
 
        return 0;
636
 
    }
 
928
    /* Right now, OTR should work on all protocols, possibly
 
929
     * with the help of fragmentation. */
637
930
    return 1;
638
931
}
639
932
 
640
933
#ifdef USING_GTK
641
934
 
642
 
static PurplePluginUiInfo ui_info =
 
935
static PidginPluginUiInfo ui_info =
643
936
{
644
937
        otrg_gtk_ui_make_widget
645
938
};
662
955
        2,                                                /* major version  */
663
956
        0,                                                /* minor version  */
664
957
 
665
 
        PURPLE_PLUGIN_STANDARD,                             /* type           */
 
958
        PURPLE_PLUGIN_STANDARD,                           /* type           */
666
959
        PLUGIN_TYPE,                                      /* ui_requirement */
667
960
        0,                                                /* flags          */
668
961
        NULL,                                             /* dependencies   */
669
 
        PURPLE_PRIORITY_DEFAULT,                            /* priority       */
 
962
        PURPLE_PRIORITY_DEFAULT,                          /* priority       */
670
963
        "otr",                                            /* id             */
671
 
        "Off-the-Record Messaging",                       /* name           */
672
 
        PIDGIN_OTR_VERSION,                                 /* version        */
673
 
                                                          /* summary        */
674
 
        "Provides private and secure conversations",
675
 
                                                          /* description    */
676
 
        "Preserves the privacy of IM communications by providing "
677
 
            "encryption, authentication, deniability, and perfect "
678
 
            "forward secrecy.",
 
964
        NULL,                                             /* name           */
 
965
        PIDGIN_OTR_VERSION,                               /* version        */
 
966
        NULL,                                             /* summary        */
 
967
        NULL,                                             /* description    */
679
968
                                                          /* author         */
680
 
        "Nikita Borisov and Ian Goldberg\n\t\t\t<otr@cypherpunks.ca>",
681
 
        "http://www.cypherpunks.ca/otr/",                 /* homepage       */
 
969
        "Ian Goldberg, Rob Smits,\n"
 
970
            "\t\t\tChris Alexander, Nikita Borisov\n"
 
971
            "\t\t\t<otr@cypherpunks.ca>",
 
972
        "http://otr.cypherpunks.ca/",                     /* homepage       */
682
973
 
683
 
        otr_plugin_load,                                 /* load           */
684
 
        otr_plugin_unload,                               /* unload         */
 
974
        otr_plugin_load,                                  /* load           */
 
975
        otr_plugin_unload,                                /* unload         */
685
976
        NULL,                                             /* destroy        */
686
977
 
687
978
        UI_INFO,                                          /* ui_info        */
699
990
    otrg_dialog_set_ui_ops(otrg_gtk_dialog_get_ui_ops());
700
991
#endif
701
992
 
 
993
#ifndef WIN32
 
994
    /* Make key generation use /dev/urandom instead of /dev/random */
 
995
    gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 
996
#endif
 
997
 
702
998
    /* Initialize the OTR library */
703
999
    OTRL_INIT;
 
1000
 
 
1001
#ifdef ENABLE_NLS
 
1002
    bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
 
1003
    bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
 
1004
#endif
 
1005
 
 
1006
    info.name        = _("Off-the-Record Messaging");
 
1007
    info.summary     = _("Provides private and secure conversations");
 
1008
    info.description = _("Preserves the privacy of IM communications "
 
1009
                         "by providing encryption, authentication, "
 
1010
                         "deniability, and perfect forward secrecy.");
704
1011
}
705
1012
 
706
1013
PURPLE_INIT_PLUGIN(otr, __init_plugin, info)