Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • otr.c

    r0e788f5 r51f937e  
    88  OTR support (cf. http://www.cypherpunks.ca/otr/)
    99 
    10   (c) 2008-2011 Sven Moritz Hallberg <pesco@khjk.org>
    11   (c) 2008 funded by stonedcoder.org
     10  (c) 2008-2011,2013 Sven Moritz Hallberg <pesco@khjk.org>
     11  funded by stonedcoder.org
    1212   
    1313  files used to store OTR data:
    1414    <configdir>/<nick>.otr_keys
    1515    <configdir>/<nick>.otr_fprints
     16    <configdir>/<nick>.otr_instags  <- don't copy this one between hosts
    1617   
    1718  top-level todos: (search for TODO for more ;-))
     
    1920    per-account policy settings
    2021    per-user policy settings
     22    add a way to select recipient instance
    2123*/
    2224
     
    6062        const char *recipient, const char *message);
    6163
    62 int op_display_otr_message(void *opdata, const char *accountname, const char *protocol,
    63         const char *username, const char *msg);
    64 
    6564void op_new_fingerprint(void *opdata, OtrlUserState us, const char *accountname,
    6665        const char *protocol, const char *username, unsigned char fingerprint[20]);
     
    8079const char *op_account_name(void *opdata, const char *account, const char *protocol);
    8180
     81void op_create_instag(void *opdata, const char *account, const char *protocol);
     82
     83void op_convert_msg(void *opdata, ConnContext *ctx, OtrlConvertType typ,
     84        char **dst, const char *src);
     85void op_convert_free(void *opdata, ConnContext *ctx, char *msg);
     86
     87void op_handle_smp_event(void *opdata, OtrlSMPEvent ev, ConnContext *ctx,
     88        unsigned short percent, char *question);
     89
     90void op_handle_msg_event(void *opdata, OtrlMessageEvent ev, ConnContext *ctx,
     91        const char *message, gcry_error_t err);
     92
     93const char *op_otr_error_message(void *opdata, ConnContext *ctx,
     94        OtrlErrorCode err_code);
    8295
    8396/** otr sub-command handlers: **/
     
    141154void yes_forget_key(void *data);
    142155
     156/* timeout handler that calls otrl_message_poll */
     157gboolean ev_message_poll(gpointer data, gint fd, b_input_condition cond);
     158
    143159/* helper to make sure accountname and protocol match the incoming "opdata" */
    144160struct im_connection *check_imc(void *opdata, const char *accountname,
     
    156172irc_user_t *peeruser(irc_t *irc, const char *handle, const char *protocol);
    157173
    158 /* handle SMP TLVs from a received message */
    159 void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs);
     174/* show an otr-related message to the user */
     175void display_otr_message(void *opdata, ConnContext *ctx, const char *fmt, ...);
     176
     177/* write an otr-related message to the system log */
     178void log_otr_message(void *opdata, const char *fmt, ...);
    160179
    161180/* combined handler for the 'otr smp' and 'otr smpq' commands */
     
    208227        otr_ops.is_logged_in = &op_is_logged_in;
    209228        otr_ops.inject_message = &op_inject_message;
    210         otr_ops.notify = NULL;
    211         otr_ops.display_otr_message = &op_display_otr_message;
    212229        otr_ops.update_context_list = NULL;
    213         otr_ops.protocol_name = NULL;
    214         otr_ops.protocol_name_free = NULL;
    215230        otr_ops.new_fingerprint = &op_new_fingerprint;
    216231        otr_ops.write_fingerprints = &op_write_fingerprints;
     
    218233        otr_ops.gone_insecure = &op_gone_insecure;
    219234        otr_ops.still_secure = &op_still_secure;
    220         otr_ops.log_message = &op_log_message;
    221235        otr_ops.max_message_size = &op_max_message_size;
    222236        otr_ops.account_name = &op_account_name;
    223237        otr_ops.account_name_free = NULL;
    224        
     238
     239        /* stuff added with libotr 4.0.0 */
     240        otr_ops.received_symkey = NULL;         /* we don't use the extra key */
     241        otr_ops.otr_error_message = &op_otr_error_message;
     242        otr_ops.otr_error_message_free = NULL;
     243        otr_ops.resent_msg_prefix = NULL;       /* default: [resent] */
     244        otr_ops.resent_msg_prefix_free = NULL;
     245        otr_ops.handle_smp_event = &op_handle_smp_event;
     246        otr_ops.handle_msg_event = &op_handle_msg_event;
     247        otr_ops.create_instag = &op_create_instag;
     248        otr_ops.convert_msg = &op_convert_msg;
     249        otr_ops.convert_free = &op_convert_free;
     250        otr_ops.timer_control = NULL;           /* we just poll */
     251               
    225252        root_command_add( "otr", 1, cmd_otr, 0 );
    226253        register_irc_plugin( &otr_plugin );
     
    246273        s = set_add( &irc->b->set, "otr_does_html", "true", set_eval_bool, irc );
    247274       
     275        /* regularly call otrl_message_poll */
     276        gint definterval = otrl_message_poll_get_default_interval(irc->otr->us);
     277        irc->otr->timer = b_timeout_add(definterval, ev_message_poll, irc->otr);
     278
    248279        return TRUE;
    249280}
     
    252283{
    253284        otr_t *otr = irc->otr;
     285        b_event_remove(otr->timer);
    254286        otrl_userstate_free(otr->us);
    255287        if(otr->keygen) {
     
    286318                g_snprintf(s, 511, "%s%s.otr_fprints", global.conf->configdir, irc->user->nick);
    287319                e = otrl_privkey_read_fingerprints(irc->otr->us, s, NULL, NULL);
     320                if(e && e!=enoent) {
     321                        irc_rootmsg(irc, "otr load: %s: %s", s, gcry_strerror(e));
     322                }
     323                g_snprintf(s, 511, "%s%s.otr_instags", global.conf->configdir, irc->user->nick);
     324                e = otrl_instag_read(irc->otr->us, s);
    288325                if(e && e!=enoent) {
    289326                        irc_rootmsg(irc, "otr load: %s: %s", s, gcry_strerror(e));
     
    386423        ignore_msg = otrl_message_receiving(irc->otr->us, &otr_ops, ic,
    387424                ic->acc->user, ic->acc->prpl->name, iu->bu->handle, msg, &newmsg,
    388                 &tlvs, NULL, NULL);
    389 
    390         otr_handle_smp(ic, iu->bu->handle, tlvs);
    391        
     425                &tlvs, NULL, NULL, NULL);
     426
    392427        if(ignore_msg) {
    393428                /* this was an internal OTR protocol message */
     
    397432                return msg;
    398433        } else {
    399                 /* OTR has processed this message */
    400                 ConnContext *context = otrl_context_find(irc->otr->us, iu->bu->handle,
    401                         ic->acc->user, ic->acc->prpl->name, 0, NULL, NULL, NULL);
    402 
    403434                /* we're done with the original msg, which will be caller-freed. */
    404                 /* NB: must not change the newmsg pointer, since we free it. */
    405                 msg = newmsg;
    406 
    407                 if(context && context->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
    408                         /* HTML decoding */
    409                         /* perform any necessary stripping that the top level would miss */
    410                         if(set_getbool(&ic->bee->set, "otr_does_html") &&
    411                            !(ic->flags & OPT_DOES_HTML) &&
    412                            set_getbool(&ic->bee->set, "strip_html")) {
    413                                 strip_html(msg);
    414                         }
    415 
    416                         /* coloring */
    417                         if(set_getbool(&ic->bee->set, "otr_color_encrypted")) {
    418                                 int color;                /* color according to f'print trust */
    419                                 char *pre="", *sep="";    /* optional parts */
    420                                 const char *trust = context->active_fingerprint->trust;
    421 
    422                                 if(trust && trust[0] != '\0')
    423                                         color=3;   /* green */
    424                                 else
    425                                         color=5;   /* red */
    426 
    427                                 /* in a query window, keep "/me " uncolored at the beginning */
    428                                 if(g_strncasecmp(msg, "/me ", 4) == 0
    429                                    && irc_user_msgdest(iu) == irc->user->nick) {
    430                                         msg += 4;  /* skip */
    431                                         pre = "/me ";
    432                                 }
    433 
    434                                 /* comma in first place could mess with the color code */
    435                                 if(msg[0] == ',') {
    436                                     /* insert a space between color spec and message */
    437                                     sep = " ";
    438                                 }
    439 
    440                                 msg = g_strdup_printf("%s\x03%.2d%s%s\x0F", pre,
    441                                         color, sep, msg);
    442                         }
    443                 }
    444 
    445                 if(msg == newmsg) {
    446                         msg = g_strdup(newmsg);
    447                 }
    448                 otrl_message_free(newmsg);
    449                 return msg;
     435                return newmsg;
    450436        }
    451437}
     
    459445        irc_t *irc = iu->irc;
    460446        struct im_connection *ic = iu->bu->ic;
     447        otrl_instag_t instag = OTRL_INSTAG_RECENT; // XXX?
    461448
    462449        /* don't do OTR on certain (not classic IM) protocols, e.g. twitter */
     
    465452        }
    466453
    467         ctx = otrl_context_find(irc->otr->us,
    468                         iu->bu->handle, ic->acc->user, ic->acc->prpl->name,
    469                         1, NULL, NULL, NULL);
    470 
    471         /* HTML encoding */
    472         /* consider OTR plaintext to be HTML if otr_does_html is set */
    473         if(ctx && ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
    474            set_getbool(&ic->bee->set, "otr_does_html") &&
    475            (g_strncasecmp(msg, "<html>", 6) != 0)) {
    476                 emsg = escape_html(msg);
    477         }
    478        
    479454        st = otrl_message_sending(irc->otr->us, &otr_ops, ic,
    480                 ic->acc->user, ic->acc->prpl->name, iu->bu->handle,
    481                 emsg, NULL, &otrmsg, NULL, NULL);
     455                ic->acc->user, ic->acc->prpl->name, iu->bu->handle, instag,
     456                emsg, NULL, &otrmsg, OTRL_FRAGMENT_SEND_ALL, &ctx, NULL, NULL);
     457        /* in libotr 4.0.0 with OTRL_FRAGMENT_SEND_ALL, otrmsg must be passed
     458         * but the value it gets carries no meaning. it can be set even though
     459         * the message has been injected. */
     460
    482461        if(emsg != msg) {
    483462                g_free(emsg);   /* we're done with this one */
    484463        }
    485464        if(st) {
    486                 return NULL;
    487         }
    488 
    489         if(otrmsg) {
    490                 if(!ctx) {
    491                         otrl_message_free(otrmsg);
    492                         return NULL;
    493                 }
    494                 st = otrl_message_fragment_and_send(&otr_ops, ic, ctx,
    495                         otrmsg, OTRL_FRAGMENT_SEND_ALL, NULL);
    496                 otrl_message_free(otrmsg);
    497         } else {
    498                 /* note: otrl_message_sending handles policy, so that if REQUIRE_ENCRYPTION is set,
    499                    this case does not occur */
    500                 return msg;
    501         }
    502        
    503         /* TODO: Error reporting should be done here now (if st!=0), probably. */
     465                /* TODO: Error reporting? */
     466        }
    504467       
    505468        return NULL;
     
    620583}
    621584
    622 int op_display_otr_message(void *opdata, const char *accountname,
    623         const char *protocol, const char *username, const char *message)
    624 {
    625         struct im_connection *ic = check_imc(opdata, accountname, protocol);
    626         char *msg = g_strdup(message);
    627         irc_t *irc = ic->bee->ui_data;
    628         irc_user_t *u = peeruser(irc, username, protocol);
    629 
    630         strip_html(msg);
    631         if(u) {
    632                 /* display as a notice from this particular user */
    633                 irc_usernotice(u, "%s", msg);
    634         } else {
    635                 irc_rootmsg(irc, "[otr] %s", msg);
    636         }
    637 
    638         g_free(msg);
    639         return 0;
    640 }
    641 
    642585void op_new_fingerprint(void *opdata, OtrlUserState us,
    643586        const char *accountname, const char *protocol,
     
    691634void op_gone_insecure(void *opdata, ConnContext *context)
    692635{
     636        /* XXX on 'otr disconnect', this gets called for every instance and we
     637         * get the message multiple times... */
     638
    693639        struct im_connection *ic =
    694640                check_imc(opdata, context->accountname, context->protocol);
     
    730676}
    731677
    732 void op_log_message(void *opdata, const char *message)
    733 {
    734         char *msg = g_strdup(message);
    735        
    736         strip_html(msg);
    737         log_message(LOGLVL_INFO, "otr: %s", msg);
    738         g_free(msg);
    739 }
    740 
    741678int op_max_message_size(void *opdata, ConnContext *context)
    742679{
    743680        struct im_connection *ic =
    744681                check_imc(opdata, context->accountname, context->protocol);
    745 
     682 
    746683        return ic->acc->prpl->mms;
    747684}
     
    754691        return peernick(irc, account, protocol);
    755692}
     693
     694void op_create_instag(void *opdata, const char *account, const char *protocol)
     695{
     696        struct im_connection *ic =
     697                check_imc(opdata, account, protocol);
     698        irc_t *irc = ic->bee->ui_data;
     699        gcry_error_t e;
     700        char s[512];
     701 
     702        g_snprintf(s, 511, "%s%s.otr_instags", global.conf->configdir,
     703                irc->user->nick);
     704        e = otrl_instag_generate(irc->otr->us, s, account, protocol);
     705        if(e) {
     706                irc_rootmsg(irc, "otr: %s/%s: otrl_instag_generate failed: %s",
     707                        account, protocol, gcry_strerror(e));
     708        }
     709}
     710
     711void op_convert_msg(void *opdata, ConnContext *ctx, OtrlConvertType typ,
     712        char **dst, const char *src)
     713{
     714        struct im_connection *ic =
     715                check_imc(opdata, ctx->accountname, ctx->protocol);
     716        irc_t *irc = ic->bee->ui_data;
     717        irc_user_t *iu = peeruser(irc, ctx->username, ctx->protocol);
     718
     719        if(typ == OTRL_CONVERT_RECEIVING) {
     720                char *msg = g_strdup(src);
     721
     722                /* HTML decoding */
     723                if(set_getbool(&ic->bee->set, "otr_does_html") &&
     724                   !(ic->flags & OPT_DOES_HTML) &&
     725                   set_getbool(&ic->bee->set, "strip_html")) {
     726                        strip_html(msg);
     727                        *dst = msg;
     728                }
     729
     730                /* coloring */
     731                if(set_getbool(&ic->bee->set, "otr_color_encrypted")) {
     732                        int color;                /* color according to f'print trust */
     733                        char *pre="", *sep="";    /* optional parts */
     734                        const char *trust = ctx->active_fingerprint->trust;
     735
     736                        if(trust && trust[0] != '\0')
     737                                color=3;   /* green */
     738                        else
     739                                color=5;   /* red */
     740
     741                        /* in a query window, keep "/me " uncolored at the beginning */
     742                        if(g_strncasecmp(msg, "/me ", 4) == 0
     743                           && irc_user_msgdest(iu) == irc->user->nick) {
     744                                msg += 4;  /* skip */
     745                                pre = "/me ";
     746                        }
     747
     748                        /* comma in first place could mess with the color code */
     749                        if(msg[0] == ',') {
     750                            /* insert a space between color spec and message */
     751                            sep = " ";
     752                        }
     753
     754                        *dst = g_strdup_printf("%s\x03%.2d%s%s\x0F", pre,
     755                                color, sep, msg);
     756                        g_free(msg);
     757                }
     758        } else {
     759                /* HTML encoding */
     760                /* consider OTR plaintext to be HTML if otr_does_html is set */
     761                if(ctx && ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
     762                   set_getbool(&ic->bee->set, "otr_does_html") &&
     763                   (g_strncasecmp(src, "<html>", 6) != 0)) {
     764                        *dst = escape_html(src);
     765                }
     766        }
     767}
     768
     769void op_convert_free(void *opdata, ConnContext *ctx, char *msg)
     770{
     771        g_free(msg);
     772}
     773       
     774/* Socialist Millionaires' Protocol */
     775void op_handle_smp_event(void *opdata, OtrlSMPEvent ev, ConnContext *ctx,
     776        unsigned short percent, char *question)
     777{
     778        struct im_connection *ic =
     779                check_imc(opdata, ctx->accountname, ctx->protocol);
     780        irc_t *irc = ic->bee->ui_data;
     781        OtrlUserState us = irc->otr->us;
     782        irc_user_t *u = peeruser(irc, ctx->username, ctx->protocol);
     783
     784        if(!u) return;
     785
     786        switch(ev) {
     787        case OTRL_SMPEVENT_ASK_FOR_SECRET:
     788                irc_rootmsg(irc, "smp: initiated by %s"
     789                        " - respond with \x02otr smp %s <secret>\x02",
     790                        u->nick, u->nick);
     791                break;
     792        case OTRL_SMPEVENT_ASK_FOR_ANSWER:
     793                irc_rootmsg(irc, "smp: initiated by %s with question: \x02\"%s\"\x02", u->nick,
     794                        question);
     795                irc_rootmsg(irc, "smp: respond with \x02otr smp %s <answer>\x02",
     796                        u->nick);
     797                break;
     798        case OTRL_SMPEVENT_CHEATED:
     799                irc_rootmsg(irc, "smp %s: opponent violated protocol, aborting",
     800                        u->nick);
     801                otrl_message_abort_smp(us, &otr_ops, u->bu->ic, ctx);
     802                otrl_sm_state_free(ctx->smstate);
     803                break;
     804        case OTRL_SMPEVENT_NONE:
     805                break;
     806        case OTRL_SMPEVENT_IN_PROGRESS:
     807                break;
     808        case OTRL_SMPEVENT_SUCCESS:
     809                if(ctx->smstate->received_question) {
     810                        irc_rootmsg(irc, "smp %s: correct answer, you are trusted",
     811                                u->nick);
     812                } else {
     813                        irc_rootmsg(irc, "smp %s: secrets proved equal, fingerprint trusted",
     814                                u->nick);
     815                }
     816                otrl_sm_state_free(ctx->smstate);
     817                break;
     818        case OTRL_SMPEVENT_FAILURE:
     819                if(ctx->smstate->received_question) {
     820                        irc_rootmsg(irc, "smp %s: wrong answer, you are not trusted",
     821                                u->nick);
     822                } else {
     823                        irc_rootmsg(irc, "smp %s: secrets did not match, fingerprint not trusted",
     824                                u->nick);
     825                }
     826                otrl_sm_state_free(ctx->smstate);
     827                break;
     828        case OTRL_SMPEVENT_ABORT:
     829                irc_rootmsg(irc, "smp: received abort from %s", u->nick);
     830                otrl_sm_state_free(ctx->smstate);
     831                break;
     832        case OTRL_SMPEVENT_ERROR:
     833                irc_rootmsg(irc, "smp %s: protocol error, aborting",
     834                        u->nick);
     835                otrl_message_abort_smp(us, &otr_ops, u->bu->ic, ctx);
     836                otrl_sm_state_free(ctx->smstate);
     837                break;
     838        }
     839}
     840
     841void op_handle_msg_event(void *opdata, OtrlMessageEvent ev, ConnContext *ctx,
     842        const char *message, gcry_error_t err)
     843{
     844        switch(ev) {
     845        case OTRL_MSGEVENT_ENCRYPTION_REQUIRED:
     846                display_otr_message(opdata, ctx,
     847                        "policy requires encryption - message not sent");
     848                break;
     849        case OTRL_MSGEVENT_ENCRYPTION_ERROR:
     850                display_otr_message(opdata, ctx,
     851                        "error during encryption - message not sent");
     852                break;
     853        case OTRL_MSGEVENT_CONNECTION_ENDED:
     854                display_otr_message(opdata, ctx,
     855                        "other end has disconnected OTR - "
     856                        "close connection or reconnect!");
     857                break;
     858        case OTRL_MSGEVENT_SETUP_ERROR:
     859                display_otr_message(opdata, ctx,
     860                        "OTR connection failed: %s", gcry_strerror(err));
     861                break;
     862        case OTRL_MSGEVENT_MSG_REFLECTED:
     863                display_otr_message(opdata, ctx,
     864                        "received our own OTR message (!?)");
     865                break;
     866        case OTRL_MSGEVENT_MSG_RESENT:
     867                display_otr_message(opdata, ctx,
     868                        "the previous message was resent");
     869                break;
     870        case OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE:
     871                display_otr_message(opdata, ctx,
     872                        "unexpected encrypted message received");
     873                break;
     874        case OTRL_MSGEVENT_RCVDMSG_UNREADABLE:
     875                display_otr_message(opdata, ctx,
     876                        "unreadable encrypted message received");
     877                break;
     878        case OTRL_MSGEVENT_RCVDMSG_MALFORMED:
     879                display_otr_message(opdata, ctx,
     880                        "malformed OTR message received");
     881                break;
     882        case OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD:
     883                if(global.conf->verbose) {
     884                        log_otr_message(opdata, "%s/%s: heartbeat received",
     885                                ctx->accountname, ctx->protocol);
     886                }
     887                break;
     888        case OTRL_MSGEVENT_LOG_HEARTBEAT_SENT:
     889                if(global.conf->verbose) {
     890                        log_otr_message(opdata, "%s/%s: heartbeat sent",
     891                                ctx->accountname, ctx->protocol);
     892                }
     893                break;
     894        case OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR:
     895                display_otr_message(opdata, ctx,
     896                        "OTR error message received: %s", message);
     897                break;
     898        case OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED:
     899                display_otr_message(opdata, ctx,
     900                        "unencrypted message received: %s", message);
     901                break;
     902        case OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED:
     903                display_otr_message(opdata, ctx,
     904                        "unrecognized OTR message received");
     905                break;
     906        case OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE:
     907                display_otr_message(opdata, ctx,
     908                        "OTR message for a different instance received");
     909                break;
     910        default:
     911                /* shouldn't happen */
     912                break;
     913        }
     914}
     915
     916const char *op_otr_error_message(void *opdata, ConnContext *ctx,
     917        OtrlErrorCode err_code)
     918{
     919        switch(err_code) {
     920        case OTRL_ERRCODE_ENCRYPTION_ERROR:
     921                return "i failed to encrypt a message";
     922        case OTRL_ERRCODE_MSG_NOT_IN_PRIVATE:
     923                return "you sent an encrypted message i didn't expect";
     924        case OTRL_ERRCODE_MSG_UNREADABLE:
     925                return "could not read encrypted message";
     926        case OTRL_ERRCODE_MSG_MALFORMED:
     927                return "you sent a malformed OTR message";
     928        default:
     929                return "i suffered an unexpected OTR error";
     930        }
     931}
     932
    756933
    757934
     
    774951        }
    775952       
    776         otrl_message_disconnect(irc->otr->us, &otr_ops,
     953        /* XXX we disconnect all instances; is that what we want? */
     954        otrl_message_disconnect_all_instances(irc->otr->us, &otr_ops,
    777955                u->bu->ic, u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, u->bu->handle);
    778956       
    779         /* for some reason, libotr (3.1.0) doesn't do this itself: */
    780         if(u->flags & IRC_USER_OTR_ENCRYPTED) {
    781                 ConnContext *ctx;
    782                 ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user,
    783                         u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL);
    784                 if(ctx)
    785                         op_gone_insecure(u->bu->ic, ctx);
    786                 else /* huh? */
    787                         u->flags &= ( IRC_USER_OTR_ENCRYPTED | IRC_USER_OTR_TRUSTED );
    788         }
     957        /* for some reason, libotr (4.0.0) doesn't do this itself: */
     958        if(!(u->flags & IRC_USER_OTR_ENCRYPTED))
     959                return;
     960
     961        ConnContext *ctx, *p;
     962        ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user,
     963                u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL);
     964        if(!ctx) { /* huh? */
     965                u->flags &= ( IRC_USER_OTR_ENCRYPTED | IRC_USER_OTR_TRUSTED );
     966                return;
     967        }
     968
     969        for(p=ctx; p && p->m_context == ctx->m_context; p=p->next)
     970                op_gone_insecure(u->bu->ic, p);
    789971}
    790972
     
    803985        }
    804986       
    805         bee_user_msg(irc->b, u->bu, "?OTR?v2?", 0);
     987        /* passing this through the filter so it goes through libotr which
     988         * will replace the simple query string with a proper one */
     989        otr_filter_msg_out(u, "?OTR?", 0);
    806990}
    807991
     
    8311015       
    8321016        ctx = otrl_context_find(irc->otr->us, u->bu->handle,
    833                 u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL);
     1017                u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL);
    8341018        if(!ctx) {
    8351019                irc_rootmsg(irc, "%s: no otr context with user", args[1]);
     
    8951079                        *(myhandle++) = '\0';
    8961080                        handle = arg;
    897                         ctx = otrl_context_find(irc->otr->us, handle, myhandle, protocol, 0, NULL, NULL, NULL);
     1081                        ctx = otrl_context_find(irc->otr->us, handle, myhandle, protocol, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL);
    8981082                        if(!ctx) {
    8991083                                irc_rootmsg(irc, "no such context");
     
    9091093                        }
    9101094                        ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user,
    911                                 u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL);
     1095                                u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL);
    9121096                        if(!ctx) {
    9131097                                irc_rootmsg(irc, "no otr context with %s", args[1]);
     
    9821166
    9831167        g_free(p);
     1168
     1169        // XXX forget all contexts
    9841170       
    9851171        if(ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
     
    10281214               
    10291215                ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user,
    1030                         u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL);
     1216                        u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL);
    10311217                if(!ctx) {
    10321218                        irc_rootmsg(irc, "no otr context with %s", args[2]);
     
    10711257               
    10721258                ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user,
    1073                         u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL);
     1259                        u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL);
    10741260                if(!ctx) {
    10751261                        irc_rootmsg(irc, "no otr context with %s", args[2]);
     
    11191305/*** local helpers / subroutines: ***/
    11201306
    1121 /* Socialist Millionaires' Protocol */
    1122 void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs)
    1123 {
     1307void log_otr_message(void *opdata, const char *fmt, ...)
     1308{
     1309        va_list va;
     1310
     1311        va_start(va, fmt);
     1312        char *msg = g_strdup_vprintf(fmt, va);
     1313        va_end(va);
     1314       
     1315        log_message(LOGLVL_INFO, "otr: %s", msg);
     1316}
     1317
     1318void display_otr_message(void *opdata, ConnContext *ctx, const char *fmt, ...)
     1319{
     1320        struct im_connection *ic =
     1321                check_imc(opdata, ctx->accountname, ctx->protocol);
    11241322        irc_t *irc = ic->bee->ui_data;
    1125         OtrlUserState us = irc->otr->us;
    1126         OtrlMessageAppOps *ops = &otr_ops;
    1127         OtrlTLV *tlv = NULL;
    1128         ConnContext *context;
    1129         NextExpectedSMP nextMsg;
    1130         irc_user_t *u;
    1131         bee_user_t *bu;
    1132 
    1133         bu = bee_user_by_handle(ic->bee, ic, handle);
    1134         if(!bu || !(u = bu->ui_data)) return;
    1135         context = otrl_context_find(us, handle,
    1136                 ic->acc->user, ic->acc->prpl->name, 1, NULL, NULL, NULL);
    1137         if(!context) {
    1138                 /* huh? out of memory or what? */
    1139                 irc_rootmsg(irc, "smp: failed to get otr context for %s", u->nick);
    1140                 otrl_message_abort_smp(us, ops, u->bu->ic, context);
    1141                 otrl_sm_state_free(context->smstate);
    1142                 return;
    1143         }
    1144         nextMsg = context->smstate->nextExpected;
    1145 
    1146         if (context->smstate->sm_prog_state == OTRL_SMP_PROG_CHEATED) {
    1147                 irc_rootmsg(irc, "smp %s: opponent violated protocol, aborting",
    1148                         u->nick);
    1149                 otrl_message_abort_smp(us, ops, u->bu->ic, context);
    1150                 otrl_sm_state_free(context->smstate);
    1151                 return;
    1152         }
    1153 
    1154         tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1Q);
    1155         if (tlv) {
    1156                 if (nextMsg != OTRL_SMP_EXPECT1) {
    1157                         irc_rootmsg(irc, "smp %s: spurious SMP1Q received, aborting", u->nick);
    1158                         otrl_message_abort_smp(us, ops, u->bu->ic, context);
    1159                         otrl_sm_state_free(context->smstate);
    1160                 } else {
    1161                         char *question = g_strndup((char *)tlv->data, tlv->len);
    1162                         irc_rootmsg(irc, "smp: initiated by %s with question: \x02\"%s\"\x02", u->nick,
    1163                                 question);
    1164                         irc_rootmsg(irc, "smp: respond with \x02otr smp %s <answer>\x02",
    1165                                 u->nick);
    1166                         g_free(question);
    1167                         /* smp stays in EXPECT1 until user responds */
    1168                 }
    1169         }
    1170         tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1);
    1171         if (tlv) {
    1172                 if (nextMsg != OTRL_SMP_EXPECT1) {
    1173                         irc_rootmsg(irc, "smp %s: spurious SMP1 received, aborting", u->nick);
    1174                         otrl_message_abort_smp(us, ops, u->bu->ic, context);
    1175                         otrl_sm_state_free(context->smstate);
    1176                 } else {
    1177                         irc_rootmsg(irc, "smp: initiated by %s"
    1178                                 " - respond with \x02otr smp %s <secret>\x02",
    1179                                 u->nick, u->nick);
    1180                         /* smp stays in EXPECT1 until user responds */
    1181                 }
    1182         }
    1183         tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2);
    1184         if (tlv) {
    1185                 if (nextMsg != OTRL_SMP_EXPECT2) {
    1186                         irc_rootmsg(irc, "smp %s: spurious SMP2 received, aborting", u->nick);
    1187                         otrl_message_abort_smp(us, ops, u->bu->ic, context);
    1188                         otrl_sm_state_free(context->smstate);
    1189                 } else {
    1190                         /* SMP2 received, otrl_message_receiving will have sent SMP3 */
    1191                         context->smstate->nextExpected = OTRL_SMP_EXPECT4;
    1192                 }
    1193         }
    1194         tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3);
    1195         if (tlv) {
    1196                 if (nextMsg != OTRL_SMP_EXPECT3) {
    1197                         irc_rootmsg(irc, "smp %s: spurious SMP3 received, aborting", u->nick);
    1198                         otrl_message_abort_smp(us, ops, u->bu->ic, context);
    1199                         otrl_sm_state_free(context->smstate);
    1200                 } else {
    1201                         /* SMP3 received, otrl_message_receiving will have sent SMP4 */
    1202                         if(context->smstate->sm_prog_state == OTRL_SMP_PROG_SUCCEEDED) {
    1203                                 if(context->smstate->received_question) {
    1204                                         irc_rootmsg(irc, "smp %s: correct answer, you are trusted",
    1205                                                 u->nick);
    1206                                 } else {
    1207                                         irc_rootmsg(irc, "smp %s: secrets proved equal, fingerprint trusted",
    1208                                                 u->nick);
    1209                                 }
    1210                         } else {
    1211                                 if(context->smstate->received_question) {
    1212                                         irc_rootmsg(irc, "smp %s: wrong answer, you are not trusted",
    1213                                                 u->nick);
    1214                                 } else {
    1215                                         irc_rootmsg(irc, "smp %s: secrets did not match, fingerprint not trusted",
    1216                                                 u->nick);
    1217                                 }
    1218                         }
    1219                         otrl_sm_state_free(context->smstate);
    1220                         /* smp is in back in EXPECT1 */
    1221                 }
    1222         }
    1223         tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4);
    1224         if (tlv) {
    1225                 if (nextMsg != OTRL_SMP_EXPECT4) {
    1226                         irc_rootmsg(irc, "smp %s: spurious SMP4 received, aborting", u->nick);
    1227                         otrl_message_abort_smp(us, ops, u->bu->ic, context);
    1228                         otrl_sm_state_free(context->smstate);
    1229                 } else {
    1230                         /* SMP4 received, otrl_message_receiving will have set fp trust */
    1231                         if(context->smstate->sm_prog_state == OTRL_SMP_PROG_SUCCEEDED) {
    1232                                 irc_rootmsg(irc, "smp %s: secrets proved equal, fingerprint trusted",
    1233                                         u->nick);
    1234                         } else {
    1235                                 irc_rootmsg(irc, "smp %s: secrets did not match, fingerprint not trusted",
    1236                                         u->nick);
    1237                         }
    1238                         otrl_sm_state_free(context->smstate);
    1239                         /* smp is in back in EXPECT1 */
    1240                 }
    1241         }
    1242         tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP_ABORT);
    1243         if (tlv) {
    1244                 irc_rootmsg(irc, "smp: received abort from %s", u->nick);
    1245                 otrl_sm_state_free(context->smstate);
    1246                 /* smp is in back in EXPECT1 */
    1247         }
     1323        irc_user_t *u = peeruser(irc, ctx->username, ctx->protocol);
     1324        va_list va;
     1325
     1326        va_start(va, fmt);
     1327        char *msg = g_strdup_vprintf(fmt, va);
     1328        va_end(va);
     1329
     1330        if(u) {
     1331                /* display as a notice from this particular user */
     1332                irc_usernotice(u, "%s", msg);
     1333        } else {
     1334                irc_rootmsg(irc, "[otr] %s", msg);
     1335        }
     1336
     1337        g_free(msg);
    12481338}
    12491339
     
    12541344        irc_user_t *u;
    12551345        ConnContext *ctx;
     1346        otrl_instag_t instag = OTRL_INSTAG_RECENT;  // XXX
    12561347
    12571348        u = irc_user_by_name(irc, nick);
     
    12661357       
    12671358        ctx = otrl_context_find(irc->otr->us, u->bu->handle,
    1268                 u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL);
     1359                u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, instag, 0, NULL, NULL, NULL);
    12691360        if(!ctx || ctx->msgstate != OTRL_MSGSTATE_ENCRYPTED) {
    12701361                irc_rootmsg(irc, "smp: otr inactive with %s, try \x02otr connect"
     
    13071398}
    13081399
     1400/* timeout handler that calls otrl_message_poll */
     1401gboolean ev_message_poll(gpointer data, gint fd, b_input_condition cond)
     1402{
     1403        otr_t *otr = data;
     1404
     1405        if(otr && otr->us)
     1406                otrl_message_poll(otr->us, &otr_ops, NULL);
     1407
     1408        return TRUE;    /* cycle timer */
     1409}
     1410
    13091411/* helper to assert that account and protocol names given to ops below always
    13101412   match the im_connection passed through as opdata */
     
    13131415{
    13141416        struct im_connection *ic = (struct im_connection *)opdata;
     1417
     1418        /* libotr 4.0.0 has a bug where it doesn't set opdata, so we catch
     1419         * that and try to find the desired connection in the global list. */
     1420        if(!ic) {
     1421                GSList *l;
     1422                for(l=get_connections(); l; l=l->next) {
     1423                        ic = l->data;
     1424                        if(strcmp(accountname, ic->acc->user) == 0 &&
     1425                           strcmp(protocol, ic->acc->prpl->name) == 0)
     1426                                break;
     1427                }
     1428                assert(l != NULL);  /* a match should always be found */
     1429                if(!l)
     1430                        return NULL;
     1431        }
    13151432
    13161433        if (strcmp(accountname, ic->acc->user) != 0) {
     
    15941711
    15951712        /* list all contexts */
     1713        /* XXX remove this, or split off as its own command */
     1714        /* XXX show instags? */
    15961715        irc_rootmsg(irc, "%s", "");
    15971716        irc_rootmsg(irc, "\x1f" "connection contexts:\x1f (bold=currently encrypted)");
     
    16221741void show_otr_context_info(irc_t *irc, ConnContext *ctx)
    16231742{
     1743        // XXX show all instags/subcontexts
     1744
    16241745        switch(ctx->otr_offer) {
    16251746        case OFFER_NOT:
Note: See TracChangeset for help on using the changeset viewer.