Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • otr.c

    r51f937e r0e788f5  
    88  OTR support (cf. http://www.cypherpunks.ca/otr/)
    99 
    10   (c) 2008-2011,2013 Sven Moritz Hallberg <pesco@khjk.org>
    11   funded by stonedcoder.org
     10  (c) 2008-2011 Sven Moritz Hallberg <pesco@khjk.org>
     11  (c) 2008 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
    1716   
    1817  top-level todos: (search for TODO for more ;-))
     
    2019    per-account policy settings
    2120    per-user policy settings
    22     add a way to select recipient instance
    2321*/
    2422
     
    6260        const char *recipient, const char *message);
    6361
     62int op_display_otr_message(void *opdata, const char *accountname, const char *protocol,
     63        const char *username, const char *msg);
     64
    6465void op_new_fingerprint(void *opdata, OtrlUserState us, const char *accountname,
    6566        const char *protocol, const char *username, unsigned char fingerprint[20]);
     
    7980const char *op_account_name(void *opdata, const char *account, const char *protocol);
    8081
    81 void op_create_instag(void *opdata, const char *account, const char *protocol);
    82 
    83 void op_convert_msg(void *opdata, ConnContext *ctx, OtrlConvertType typ,
    84         char **dst, const char *src);
    85 void op_convert_free(void *opdata, ConnContext *ctx, char *msg);
    86 
    87 void op_handle_smp_event(void *opdata, OtrlSMPEvent ev, ConnContext *ctx,
    88         unsigned short percent, char *question);
    89 
    90 void op_handle_msg_event(void *opdata, OtrlMessageEvent ev, ConnContext *ctx,
    91         const char *message, gcry_error_t err);
    92 
    93 const char *op_otr_error_message(void *opdata, ConnContext *ctx,
    94         OtrlErrorCode err_code);
    9582
    9683/** otr sub-command handlers: **/
     
    154141void yes_forget_key(void *data);
    155142
    156 /* timeout handler that calls otrl_message_poll */
    157 gboolean ev_message_poll(gpointer data, gint fd, b_input_condition cond);
    158 
    159143/* helper to make sure accountname and protocol match the incoming "opdata" */
    160144struct im_connection *check_imc(void *opdata, const char *accountname,
     
    172156irc_user_t *peeruser(irc_t *irc, const char *handle, const char *protocol);
    173157
    174 /* show an otr-related message to the user */
    175 void display_otr_message(void *opdata, ConnContext *ctx, const char *fmt, ...);
    176 
    177 /* write an otr-related message to the system log */
    178 void log_otr_message(void *opdata, const char *fmt, ...);
     158/* handle SMP TLVs from a received message */
     159void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs);
    179160
    180161/* combined handler for the 'otr smp' and 'otr smpq' commands */
     
    227208        otr_ops.is_logged_in = &op_is_logged_in;
    228209        otr_ops.inject_message = &op_inject_message;
     210        otr_ops.notify = NULL;
     211        otr_ops.display_otr_message = &op_display_otr_message;
    229212        otr_ops.update_context_list = NULL;
     213        otr_ops.protocol_name = NULL;
     214        otr_ops.protocol_name_free = NULL;
    230215        otr_ops.new_fingerprint = &op_new_fingerprint;
    231216        otr_ops.write_fingerprints = &op_write_fingerprints;
     
    233218        otr_ops.gone_insecure = &op_gone_insecure;
    234219        otr_ops.still_secure = &op_still_secure;
     220        otr_ops.log_message = &op_log_message;
    235221        otr_ops.max_message_size = &op_max_message_size;
    236222        otr_ops.account_name = &op_account_name;
    237223        otr_ops.account_name_free = NULL;
    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                
     224       
    252225        root_command_add( "otr", 1, cmd_otr, 0 );
    253226        register_irc_plugin( &otr_plugin );
     
    273246        s = set_add( &irc->b->set, "otr_does_html", "true", set_eval_bool, irc );
    274247       
    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 
    279248        return TRUE;
    280249}
     
    283252{
    284253        otr_t *otr = irc->otr;
    285         b_event_remove(otr->timer);
    286254        otrl_userstate_free(otr->us);
    287255        if(otr->keygen) {
     
    318286                g_snprintf(s, 511, "%s%s.otr_fprints", global.conf->configdir, irc->user->nick);
    319287                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);
    325288                if(e && e!=enoent) {
    326289                        irc_rootmsg(irc, "otr load: %s: %s", s, gcry_strerror(e));
     
    423386        ignore_msg = otrl_message_receiving(irc->otr->us, &otr_ops, ic,
    424387                ic->acc->user, ic->acc->prpl->name, iu->bu->handle, msg, &newmsg,
    425                 &tlvs, NULL, NULL, NULL);
    426 
     388                &tlvs, NULL, NULL);
     389
     390        otr_handle_smp(ic, iu->bu->handle, tlvs);
     391       
    427392        if(ignore_msg) {
    428393                /* this was an internal OTR protocol message */
     
    432397                return msg;
    433398        } 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
    434403                /* we're done with the original msg, which will be caller-freed. */
    435                 return newmsg;
     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;
    436450        }
    437451}
     
    445459        irc_t *irc = iu->irc;
    446460        struct im_connection *ic = iu->bu->ic;
    447         otrl_instag_t instag = OTRL_INSTAG_RECENT; // XXX?
    448461
    449462        /* don't do OTR on certain (not classic IM) protocols, e.g. twitter */
     
    452465        }
    453466
     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       
    454479        st = otrl_message_sending(irc->otr->us, &otr_ops, ic,
    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 
     480                ic->acc->user, ic->acc->prpl->name, iu->bu->handle,
     481                emsg, NULL, &otrmsg, NULL, NULL);
    461482        if(emsg != msg) {
    462483                g_free(emsg);   /* we're done with this one */
    463484        }
    464485        if(st) {
    465                 /* TODO: Error reporting? */
    466         }
     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. */
    467504       
    468505        return NULL;
     
    583620}
    584621
     622int 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
    585642void op_new_fingerprint(void *opdata, OtrlUserState us,
    586643        const char *accountname, const char *protocol,
     
    634691void op_gone_insecure(void *opdata, ConnContext *context)
    635692{
    636         /* XXX on 'otr disconnect', this gets called for every instance and we
    637          * get the message multiple times... */
    638 
    639693        struct im_connection *ic =
    640694                check_imc(opdata, context->accountname, context->protocol);
     
    676730}
    677731
     732void 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
    678741int op_max_message_size(void *opdata, ConnContext *context)
    679742{
    680743        struct im_connection *ic =
    681744                check_imc(opdata, context->accountname, context->protocol);
    682  
     745
    683746        return ic->acc->prpl->mms;
    684747}
     
    691754        return peernick(irc, account, protocol);
    692755}
    693 
    694 void 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 
    711 void 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 
    769 void op_convert_free(void *opdata, ConnContext *ctx, char *msg)
    770 {
    771         g_free(msg);
    772 }
    773        
    774 /* Socialist Millionaires' Protocol */
    775 void 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 
    841 void 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 
    916 const 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 
    933756
    934757
     
    951774        }
    952775       
    953         /* XXX we disconnect all instances; is that what we want? */
    954         otrl_message_disconnect_all_instances(irc->otr->us, &otr_ops,
     776        otrl_message_disconnect(irc->otr->us, &otr_ops,
    955777                u->bu->ic, u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, u->bu->handle);
    956778       
    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);
     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        }
    971789}
    972790
     
    985803        }
    986804       
    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);
     805        bee_user_msg(irc->b, u->bu, "?OTR?v2?", 0);
    990806}
    991807
     
    1015831       
    1016832        ctx = otrl_context_find(irc->otr->us, u->bu->handle,
    1017                 u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL);
     833                u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL);
    1018834        if(!ctx) {
    1019835                irc_rootmsg(irc, "%s: no otr context with user", args[1]);
     
    1079895                        *(myhandle++) = '\0';
    1080896                        handle = arg;
    1081                         ctx = otrl_context_find(irc->otr->us, handle, myhandle, protocol, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL);
     897                        ctx = otrl_context_find(irc->otr->us, handle, myhandle, protocol, 0, NULL, NULL, NULL);
    1082898                        if(!ctx) {
    1083899                                irc_rootmsg(irc, "no such context");
     
    1093909                        }
    1094910                        ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user,
    1095                                 u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL);
     911                                u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL);
    1096912                        if(!ctx) {
    1097913                                irc_rootmsg(irc, "no otr context with %s", args[1]);
     
    1166982
    1167983        g_free(p);
    1168 
    1169         // XXX forget all contexts
    1170984       
    1171985        if(ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
     
    12141028               
    12151029                ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user,
    1216                         u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL);
     1030                        u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL);
    12171031                if(!ctx) {
    12181032                        irc_rootmsg(irc, "no otr context with %s", args[2]);
     
    12571071               
    12581072                ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user,
    1259                         u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL);
     1073                        u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL);
    12601074                if(!ctx) {
    12611075                        irc_rootmsg(irc, "no otr context with %s", args[2]);
     
    13051119/*** local helpers / subroutines: ***/
    13061120
    1307 void 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 
    1318 void display_otr_message(void *opdata, ConnContext *ctx, const char *fmt, ...)
    1319 {
    1320         struct im_connection *ic =
    1321                 check_imc(opdata, ctx->accountname, ctx->protocol);
     1121/* Socialist Millionaires' Protocol */
     1122void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs)
     1123{
    13221124        irc_t *irc = ic->bee->ui_data;
    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);
     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        }
    13381248}
    13391249
     
    13441254        irc_user_t *u;
    13451255        ConnContext *ctx;
    1346         otrl_instag_t instag = OTRL_INSTAG_RECENT;  // XXX
    13471256
    13481257        u = irc_user_by_name(irc, nick);
     
    13571266       
    13581267        ctx = otrl_context_find(irc->otr->us, u->bu->handle,
    1359                 u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, instag, 0, NULL, NULL, NULL);
     1268                u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL);
    13601269        if(!ctx || ctx->msgstate != OTRL_MSGSTATE_ENCRYPTED) {
    13611270                irc_rootmsg(irc, "smp: otr inactive with %s, try \x02otr connect"
     
    13981307}
    13991308
    1400 /* timeout handler that calls otrl_message_poll */
    1401 gboolean 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 
    14111309/* helper to assert that account and protocol names given to ops below always
    14121310   match the im_connection passed through as opdata */
     
    14151313{
    14161314        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         }
    14321315
    14331316        if (strcmp(accountname, ic->acc->user) != 0) {
     
    17111594
    17121595        /* list all contexts */
    1713         /* XXX remove this, or split off as its own command */
    1714         /* XXX show instags? */
    17151596        irc_rootmsg(irc, "%s", "");
    17161597        irc_rootmsg(irc, "\x1f" "connection contexts:\x1f (bold=currently encrypted)");
     
    17411622void show_otr_context_info(irc_t *irc, ConnContext *ctx)
    17421623{
    1743         // XXX show all instags/subcontexts
    1744 
    17451624        switch(ctx->otr_offer) {
    17461625        case OFFER_NOT:
Note: See TracChangeset for help on using the changeset viewer.