diff options
-rw-r--r-- | irc.c | 5 | ||||
-rw-r--r-- | otr.c | 120 | ||||
-rw-r--r-- | query.c | 4 |
3 files changed, 113 insertions, 16 deletions
@@ -108,13 +108,14 @@ irc_t *irc_new( int fd ) set_add( &irc->set, "buddy_sendbuffer", "false", set_eval_bool, irc ); set_add( &irc->set, "buddy_sendbuffer_delay", "200", set_eval_int, irc ); set_add( &irc->set, "charset", "utf-8", set_eval_charset, irc ); + set_add( &irc->set, "color_encrypted", "true", set_eval_bool, irc ); set_add( &irc->set, "debug", "false", set_eval_bool, irc ); set_add( &irc->set, "default_target", "root", NULL, irc ); set_add( &irc->set, "display_namechanges", "false", set_eval_bool, irc ); set_add( &irc->set, "handle_unknown", "root", NULL, irc ); - set_add( &irc->set, "halfop_buddies", "false", set_eval_halfop_buddies, irc ); + set_add( &irc->set, "halfop_buddies", "encrypted", set_eval_halfop_buddies, irc ); set_add( &irc->set, "lcnicks", "true", set_eval_bool, irc ); - set_add( &irc->set, "op_buddies", "false", set_eval_op_buddies, irc ); + set_add( &irc->set, "op_buddies", "trusted", set_eval_op_buddies, irc ); set_add( &irc->set, "op_root", "true", set_eval_op_root, irc ); set_add( &irc->set, "op_user", "true", set_eval_op_user, irc ); set_add( &irc->set, "password", NULL, passchange, irc ); @@ -93,6 +93,7 @@ struct kgdata { void yes_keygen(gpointer w, void *data); void yes_forget_fingerprint(gpointer w, void *data); void yes_forget_context(gpointer w, void *data); +void yes_forget_key(gpointer w, void *data); /* helper to make sure accountname and protocol match the incoming "opdata" */ struct im_connection *check_imc(void *opdata, const char *accountname, @@ -129,6 +130,9 @@ void show_fingerprints(irc_t *irc, ConnContext *ctx); /* find a fingerprint by prefix (given as any number of hex strings) */ Fingerprint *match_fingerprint(irc_t *irc, ConnContext *ctx, const char **args); +/* find a private key by fingerprint prefix (given as any number of hex strings) */ +OtrlPrivKey *match_privkey(irc_t *irc, const char **args); + /* to log out accounts during keygen */ extern void cmd_account(irc_t *irc, char **cmd); @@ -287,7 +291,8 @@ char *otr_handle_message(struct im_connection *ic, const char *handle, const cha /* OTR has processed this message */ ConnContext *context = otrl_context_find(ic->irc->otr_us, handle, ic->acc->user, ic->acc->prpl->name, 0, NULL, NULL, NULL); - if(context && context->msgstate == OTRL_MSGSTATE_ENCRYPTED) { + if(context && context->msgstate == OTRL_MSGSTATE_ENCRYPTED && + set_getbool(&ic->irc->set, "color_encrypted")) { /* color according to f'print trust */ char color; const char *trust = context->active_fingerprint->trust; @@ -394,8 +399,8 @@ void op_create_privkey(void *opdata, const char *accountname, log_message(LOGLVL_DEBUG, "op_create_privkey '%s' '%s'", accountname, protocol); - s = g_strdup_printf("oops, no otr privkey for %s/%s - generate one now?", - accountname, protocol); + s = g_strdup_printf("oops, no otr privkey for %s - generate one now?", + accountname); query_add(ic->irc, ic, s, yes_keygen, NULL, ic->acc); } @@ -793,7 +798,7 @@ void cmd_otr_keygen(irc_t *irc, char **args) if(otrl_privkey_find(irc->otr_us, a->user, a->prpl->name)) { char *s = g_strdup_printf("account %d already has a key, replace it?", n); - query_add(irc, a->ic, s, yes_keygen, NULL, a); + query_add(irc, NULL, s, yes_keygen, NULL, a); } else { otr_keygen(irc, a->user, a->prpl->name); } @@ -801,11 +806,11 @@ void cmd_otr_keygen(irc_t *irc, char **args) void yes_forget_fingerprint(gpointer w, void *data) { - struct im_connection *ic = (struct im_connection *)w; + irc_t *irc = (irc_t *)w; Fingerprint *fp = (Fingerprint *)data; if(fp == fp->context->active_fingerprint) { - irc_usermsg(ic->irc, "that fingerprint is active, terminate otr connection first"); + irc_usermsg(irc, "that fingerprint is active, terminate otr connection first"); return; } @@ -814,12 +819,12 @@ void yes_forget_fingerprint(gpointer w, void *data) void yes_forget_context(gpointer w, void *data) { - struct im_connection *ic = (struct im_connection *)w; + irc_t *irc = (irc_t *)w; ConnContext *ctx = (ConnContext *)data; if(ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) { - irc_usermsg(ic->irc, "active otr connection with %s, terminate it first", - peernick(ic->irc, ctx->username, ctx->protocol)); + irc_usermsg(irc, "active otr connection with %s, terminate it first", + peernick(irc, ctx->username, ctx->protocol)); return; } @@ -828,6 +833,15 @@ void yes_forget_context(gpointer w, void *data) otrl_context_forget(ctx); } +void yes_forget_key(gpointer w, void *data) +{ + OtrlPrivKey *key = (OtrlPrivKey *)data; + + /* FIXME: For some reason which /completely eludes me/, this call keeps + barfing on the gcry_sexp_release inside (invalid pointer free). */ + otrl_privkey_forget(key); +} + void cmd_otr_forget(irc_t *irc, char **args) { if(!strcmp(args[1], "fingerprint")) @@ -869,7 +883,7 @@ void cmd_otr_forget(irc_t *irc, char **args) otrl_privkey_hash_to_human(human, fp->fingerprint); s = g_strdup_printf("about to forget fingerprint %s, are you sure?", human); - query_add(irc, u->ic, s, yes_forget_fingerprint, NULL, fp); + query_add(irc, NULL, s, yes_forget_fingerprint, NULL, fp); } else if(!strcmp(args[1], "context")) @@ -897,12 +911,28 @@ void cmd_otr_forget(irc_t *irc, char **args) } s = g_strdup_printf("about to forget otr data about %s, are you sure?", args[2]); - query_add(irc, u->ic, s, yes_forget_context, NULL, ctx); + query_add(irc, NULL, s, yes_forget_context, NULL, ctx); } else if(!strcmp(args[1], "key")) { - irc_usermsg(irc, "n/a: TODO"); + OtrlPrivKey *key; + char *s; + + key = match_privkey(irc, ((const char **)args)+2); + if(!key) { + /* match_privkey does error messages */ + return; + } + + /* TODO: Find out why 'otr forget key' barfs (cf. yes_forget_key) */ + irc_usermsg(irc, "otr %s %s: not implemented, please edit \x02%s%s.otr_keys\x02 manually :-/", + args[0], args[1], global.conf->configdir, irc->nick); + return; + + s = g_strdup_printf("about to forget the private key for %s/%s, are you sure?", + key->accountname, key->protocol); + query_add(irc, NULL, s, yes_forget_key, NULL, key); } else @@ -1230,6 +1260,72 @@ Fingerprint *match_fingerprint(irc_t *irc, ConnContext *ctx, const char **args) return fp; } +OtrlPrivKey *match_privkey(irc_t *irc, const char **args) +{ + OtrlPrivKey *k, *k2; + char human[45]; + char prefix[45], *p; + int n; + int i,j; + + /* assemble the args into a prefix in standard "human" form */ + n=0; + p=prefix; + for(i=0; args[i]; i++) { + for(j=0; args[i][j]; j++) { + char c = toupper(args[i][j]); + + if(n>=40) { + irc_usermsg(irc, "too many fingerprint digits given, expected at most 40"); + return NULL; + } + + if( (c>='A' && c<='F') || (c>='0' && c<='9') ) { + *(p++) = c; + } else { + irc_usermsg(irc, "invalid hex digit '%c' in block %d", args[i][j], i+1); + return NULL; + } + + n++; + if(n%8 == 0) + *(p++) = ' '; + } + } + *p = '\0'; + log_message(LOGLVL_DEBUG, "match_privkey '%s'", prefix); + log_message(LOGLVL_DEBUG, "n=%d strlen(prefix)=%d", n, strlen(prefix)); + + /* find first key which matches the given prefix */ + n = strlen(prefix); + for(k=irc->otr_us->privkey_root; k; k=k->next) { + p = otrl_privkey_fingerprint(irc->otr_us, human, k->accountname, k->protocol); + if(!p) /* gah! :-P */ + continue; + if(!strncmp(prefix, human, n)) + break; + } + if(!k) { + irc_usermsg(irc, "%s: no match", prefix); + return NULL; + } + + /* make sure the match, if any, is unique */ + for(k2=k->next; k2; k2=k2->next) { + p = otrl_privkey_fingerprint(irc->otr_us, human, k2->accountname, k2->protocol); + if(!p) /* gah! :-P */ + continue; + if(!strncmp(prefix, human, n)) + break; + } + if(k2) { + irc_usermsg(irc, "%s: multiple matches", prefix); + return NULL; + } + + return k; +} + void show_general_otr_info(irc_t *irc) { ConnContext *ctx; @@ -147,7 +147,7 @@ void query_answer( irc_t *irc, query_t *q, int ans ) else irc_usermsg( irc, "Accepted: %s", q->question ); if(q->yes) - q->yes( q->ic ? q->ic : irc, q->data ); + q->yes( q->ic ? (gpointer)q->ic : (gpointer)irc, q->data ); } else { @@ -156,7 +156,7 @@ void query_answer( irc_t *irc, query_t *q, int ans ) else irc_usermsg( irc, "Rejected: %s", q->question ); if(q->no) - q->no( q->ic ? q->ic : irc, q->data ); + q->no( q->ic ? (gpointer)q->ic : (gpointer)irc, q->data ); } q->data = NULL; |