aboutsummaryrefslogtreecommitdiffstats
path: root/otr.c
diff options
context:
space:
mode:
Diffstat (limited to 'otr.c')
-rw-r--r--otr.c319
1 files changed, 183 insertions, 136 deletions
diff --git a/otr.c b/otr.c
index ccb65887..aaab8def 100644
--- a/otr.c
+++ b/otr.c
@@ -47,24 +47,22 @@ const char *op_account_name(void *opdata, const char *account, const char *proto
/** otr sub-command handlers: **/
-/* TODO: void cmd_otr_keygen(irc_t *irc, char **args); */
-void cmd_otr_abort(irc_t *irc, char **args); /* TODO: does this cmd even make sense? */
-void cmd_otr_request(irc_t *irc, char **args); /* TODO: do we even need this? */
+void cmd_otr_connect(irc_t *irc, char **args);
+void cmd_otr_disconnect(irc_t *irc, char **args);
void cmd_otr_smp(irc_t *irc, char **args);
void cmd_otr_trust(irc_t *irc, char **args);
-/* TODO: void cmd_otr_affirm(irc_t *irc, char **args); */
-void cmd_otr_fprints(irc_t *irc, char **args);
void cmd_otr_info(irc_t *irc, char **args);
-void cmd_otr_policy(irc_t *irc, char **args);
+/* void cmd_otr_forget(irc_t *irc, char **args); */
const command_t otr_commands[] = {
- { "abort", 1, &cmd_otr_abort, 0 },
- { "request", 1, &cmd_otr_request, 0 },
- { "smp", 2, &cmd_otr_smp, 0 },
- { "trust", 6, &cmd_otr_trust, 0 },
- { "fprints", 0, &cmd_otr_fprints, 0 },
- { "info", 1, &cmd_otr_info, 0 },
- { "policy", 0, &cmd_otr_policy, 0 },
+ { "connect", 1, &cmd_otr_connect, 0 },
+ { "disconnect", 1, &cmd_otr_disconnect, 0 },
+ { "smp", 2, &cmd_otr_smp, 0 },
+ { "trust", 6, &cmd_otr_trust, 0 },
+ { "info", 0, &cmd_otr_info, 0 },
+ /*
+ { "forget", 1, &cmd_otr_forget, 0 },
+ */
{ NULL }
};
@@ -100,6 +98,9 @@ struct im_connection *check_imc(void *opdata, const char *accountname,
returns "handle/protocol" if not found */
const char *peernick(irc_t *irc, const char *handle, const char *protocol);
+/* turn a hexadecimal digit into its numerical value */
+int hexval(char a);
+
/* determine the user_t for a given handle/protocol pair
returns NULL if not found */
user_t *peeruser(irc_t *irc, const char *handle, const char *protocol);
@@ -112,11 +113,16 @@ void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs)
i.e. msgstate should be announced seperately */
int otr_update_modeflags(irc_t *irc, user_t *u);
+/* show general info about the OTR subsystem; called by 'otr info' */
+void show_general_otr_info(irc_t *irc);
+
+/* show info about a given OTR context */
+void show_otr_context_info(irc_t *irc, ConnContext *ctx);
+
/* show the list of fingerprints associated with a given context */
void show_fingerprints(irc_t *irc, ConnContext *ctx);
-
/*** routines declared in otr.h: ***/
void otr_init(void)
@@ -488,8 +494,8 @@ void op_gone_secure(void *opdata, ConnContext *context)
u = peeruser(ic->irc, context->username, context->protocol);
if(!u) {
log_message(LOGLVL_ERROR,
- "BUG: otr.c: op_gone_secure: user_t for %s/%s not found!",
- context->username, context->protocol);
+ "BUG: otr.c: op_gone_secure: user_t for %s/%s/%s not found!",
+ context->username, context->protocol, context->accountname);
return;
}
if(context->active_fingerprint->trust[0])
@@ -511,8 +517,8 @@ void op_gone_insecure(void *opdata, ConnContext *context)
u = peeruser(ic->irc, context->username, context->protocol);
if(!u) {
log_message(LOGLVL_ERROR,
- "BUG: otr.c: op_gone_insecure: user_t for %s/%s not found!",
- context->username, context->protocol);
+ "BUG: otr.c: op_gone_insecure: user_t for %s/%s/%s not found!",
+ context->username, context->protocol, context->accountname);
return;
}
u->encrypted = 0;
@@ -532,8 +538,8 @@ void op_still_secure(void *opdata, ConnContext *context, int is_reply)
u = peeruser(ic->irc, context->username, context->protocol);
if(!u) {
log_message(LOGLVL_ERROR,
- "BUG: otr.c: op_still_secure: user_t for %s/%s not found!",
- context->username, context->protocol);
+ "BUG: otr.c: op_still_secure: user_t for %s/%s/%s not found!",
+ context->username, context->protocol, context->accountname);
return;
}
if(context->active_fingerprint->trust[0])
@@ -573,7 +579,7 @@ const char *op_account_name(void *opdata, const char *account, const char *proto
/*** OTR sub-command handlers ***/
-void cmd_otr_abort(irc_t *irc, char **args)
+void cmd_otr_disconnect(irc_t *irc, char **args)
{
user_t *u;
@@ -587,7 +593,7 @@ void cmd_otr_abort(irc_t *irc, char **args)
u->ic, u->ic->acc->user, u->ic->acc->prpl->name, u->handle);
}
-void cmd_otr_request(irc_t *irc, char **args)
+void cmd_otr_connect(irc_t *irc, char **args)
{
user_t *u;
@@ -651,20 +657,6 @@ void cmd_otr_smp(irc_t *irc, char **args)
}
}
-int hexval(char a)
-{
- int x=tolower(a);
-
- if(x>='a' && x<='f')
- x = x - 'a' + 10;
- else if(x>='0' && x<='9')
- x = x - '0';
- else
- return -1;
-
- return x;
-}
-
void cmd_otr_trust(irc_t *irc, char **args)
{
user_t *u;
@@ -725,112 +717,59 @@ void cmd_otr_trust(irc_t *irc, char **args)
}
}
-void cmd_otr_fprints(irc_t *irc, char **args)
+void cmd_otr_info(irc_t *irc, char **args)
{
- if(args[1]) {
- /* list given buddy's fingerprints */
- user_t *u;
- ConnContext *ctx;
-
- u = user_find(irc, args[1]);
- if(!u || !u->ic) {
- irc_usermsg(irc, "%s: unknown user", args[1]);
- return;
- }
-
- ctx = otrl_context_find(irc->otr_us, u->handle,
- u->ic->acc->user, u->ic->acc->prpl->name, 0, NULL, NULL, NULL);
- if(!ctx) {
- irc_usermsg(irc, "no fingerprints");
- } else {
- show_fingerprints(irc, ctx);
- }
+ if(!args[1]) {
+ show_general_otr_info(irc);
} else {
- /* list all known fingerprints */
+ char *arg = g_strdup(args[1]);
+ char *myhandle, *handle, *protocol;
ConnContext *ctx;
- for(ctx=irc->otr_us->context_root; ctx; ctx=ctx->next) {
- irc_usermsg(irc, "[%s]", peernick(irc, ctx->username, ctx->protocol));
- show_fingerprints(irc, ctx);
- }
- if(!irc->otr_us->context_root) {
- irc_usermsg(irc, "no fingerprints");
+
+ /* interpret arg as 'user/protocol/account' if possible */
+ protocol = strchr(arg, '/');
+ if(protocol) {
+ *(protocol++) = '\0';
+ myhandle = strchr(protocol, '/');
+ if(!myhandle) {
+ /* TODO: try to find a unique account for this context */
+ }
}
- }
-}
-
-void cmd_otr_info(irc_t *irc, char **args)
-{
- user_t *u;
- ConnContext *ctx;
- Fingerprint *fp;
- char human[45];
- const char *offer_status;
- const char *message_state;
- const char *trust;
-
- if(!args) {
- irc_usermsg(irc, "no args?!");
- return;
- }
- if(!args[1]) {
- irc_usermsg(irc, "no args[1]?!");
- return;
- }
- u = user_find(irc, args[1]);
- if(!u || !u->ic) {
- irc_usermsg(irc, "%s: unknown user", args[1]);
- return;
- }
-
- ctx = otrl_context_find(irc->otr_us, u->handle,
- u->ic->acc->user, u->ic->acc->prpl->name, 0, NULL, NULL, NULL);
- if(!ctx) {
- irc_usermsg(irc, "no otr context with %s", args[1]);
- return;
- }
-
- switch(ctx->otr_offer) {
- case OFFER_NOT: offer_status="none sent"; break;
- case OFFER_SENT: offer_status="awaiting reply"; break;
- case OFFER_ACCEPTED: offer_status="accepted our offer"; break;
- case OFFER_REJECTED: offer_status="ignored our offer"; break;
- default: offer_status="?";
- }
-
- switch(ctx->msgstate) {
- case OTRL_MSGSTATE_PLAINTEXT: message_state="cleartext"; break;
- case OTRL_MSGSTATE_ENCRYPTED: message_state="encrypted"; break;
- case OTRL_MSGSTATE_FINISHED: message_state="shut down"; break;
- default: message_state="?";
- }
-
- irc_usermsg(irc, "%s is %s/%s; we are %s/%s to them", args[1],
- ctx->username, ctx->protocol, ctx->accountname, ctx->protocol);
- irc_usermsg(irc, " otr offer status: %s", offer_status);
- irc_usermsg(irc, " connection state: %s", message_state);
-
- if(ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
- irc_usermsg(irc, " protocol version: %d", ctx->protocol_version);
- fp = ctx->active_fingerprint;
- if(!fp) {
- irc_usermsg(irc, " active f'print: none?");
+ if(protocol && myhandle) {
+ *(myhandle++) = '\0';
+ handle = arg;
+ ctx = otrl_context_find(irc->otr_us, handle, myhandle, protocol, 0, NULL, NULL, NULL);
+ if(!ctx) {
+ irc_usermsg(irc, "no such context (%s %s %s)", handle, protocol, myhandle);
+ g_free(arg);
+ return;
+ }
} else {
- otrl_privkey_hash_to_human(human, fp->fingerprint);
- if(!fp->trust || fp->trust[0] == '\0') {
- trust="untrusted";
- } else {
- trust=fp->trust;
+ user_t *u = user_find(irc, args[1]);
+ if(!u || !u->ic) {
+ irc_usermsg(irc, "%s: unknown user", args[1]);
+ g_free(arg);
+ return;
+ }
+ ctx = otrl_context_find(irc->otr_us, u->handle, u->ic->acc->user,
+ u->ic->acc->prpl->name, 0, NULL, NULL, NULL);
+ if(!ctx) {
+ irc_usermsg(irc, "no otr context with %s", args[1]);
+ g_free(arg);
+ return;
}
- irc_usermsg(irc, " active f'print: %s (%s)", human, trust);
}
+
+ /* show how we resolved the (nick) argument, if we did */
+ if(handle!=arg) {
+ irc_usermsg(irc, "%s is %s/%s; we are %s/%s to them", args[1],
+ ctx->username, ctx->protocol, ctx->accountname, ctx->protocol);
+ }
+ show_otr_context_info(irc, ctx);
+ g_free(arg);
}
}
-void cmd_otr_policy(irc_t *irc, char **args)
-{
- irc_usermsg(irc, "n/a: not implemented");
-}
-
/*** local helpers / subroutines: ***/
@@ -952,10 +891,12 @@ user_t *peeruser(irc_t *irc, const char *handle, const char *protocol)
{
user_t *u;
+ log_message(LOGLVL_DEBUG, "peeruser '%s' '%s'", handle, protocol);
+
for(u=irc->users; u; u=u->next) {
struct prpl *prpl;
if(!u->ic || !u->handle)
- break;
+ continue;
prpl = u->ic->acc->prpl;
if(strcmp(prpl->name, protocol) == 0
&& prpl->handle_cmp(u->handle, handle) == 0) {
@@ -966,6 +907,20 @@ user_t *peeruser(irc_t *irc, const char *handle, const char *protocol)
return NULL;
}
+int hexval(char a)
+{
+ int x=tolower(a);
+
+ if(x>='a' && x<='f')
+ x = x - 'a' + 10;
+ else if(x>='0' && x<='9')
+ x = x - '0';
+ else
+ return -1;
+
+ return x;
+}
+
const char *peernick(irc_t *irc, const char *handle, const char *protocol)
{
static char fallback[512];
@@ -1053,13 +1008,105 @@ void show_fingerprints(irc_t *irc, ConnContext *ctx)
trust=fp->trust;
}
if(fp == ctx->active_fingerprint) {
- irc_usermsg(irc, "\x02%s (%s)\x02", human, trust);
+ irc_usermsg(irc, " \x02%s (%s)\x02", human, trust);
} else {
- irc_usermsg(irc, "%s (%s)", human, trust);
+ irc_usermsg(irc, " %s (%s)", human, trust);
}
}
if(count==0)
- irc_usermsg(irc, "no fingerprints");
+ irc_usermsg(irc, " no fingerprints");
+}
+
+void show_general_otr_info(irc_t *irc)
+{
+ ConnContext *ctx;
+ OtrlPrivKey *key;
+ char human[45];
+
+ /* list all privkeys */
+ irc_usermsg(irc, "\x1fprivate keys:\x1f");
+ for(key=irc->otr_us->privkey_root; key; key=key->next) {
+ const char *hash;
+
+ switch(key->pubkey_type) {
+ case OTRL_PUBKEY_TYPE_DSA:
+ irc_usermsg(irc, " %s/%s - DSA", key->accountname, key->protocol);
+ break;
+ default:
+ irc_usermsg(irc, " %s/%s - type %d", key->accountname, key->protocol,
+ key->pubkey_type);
+ }
+
+ /* No, it doesn't make much sense to search for the privkey again by
+ account/protocol, but libotr currently doesn't provide a direct routine
+ for hashing a given 'OtrlPrivKey'... */
+ hash = otrl_privkey_fingerprint(irc->otr_us, human, key->accountname, key->protocol);
+ if(hash) /* should always succeed */
+ irc_usermsg(irc, " %s", human);
+ }
+
+ /* list all contexts */
+ irc_usermsg(irc, "%s", "");
+ irc_usermsg(irc, "\x1f" "connection contexts:\x1f (bold=currently encrypted)");
+ for(ctx=irc->otr_us->context_root; ctx; ctx=ctx->next) {\
+ user_t *u;
+ char *userstring;
+
+ u = peeruser(irc, ctx->username, ctx->protocol);
+ if(u)
+ userstring = g_strdup_printf("%s/%s/%s (%s)",
+ ctx->username, ctx->protocol, ctx->accountname, u->nick);
+ else
+ userstring = g_strdup_printf("%s/%s/%s",
+ ctx->username, ctx->protocol, ctx->accountname);
+
+ if(ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
+ otrl_privkey_hash_to_human(human, ctx->active_fingerprint->fingerprint);
+ irc_usermsg(irc, " \x02%s\x02", userstring);
+ irc_usermsg(irc, " %s", human);
+ } else {
+ irc_usermsg(irc, " %s", userstring);
+ }
+
+ g_free(userstring);
+ }
+}
+
+void show_otr_context_info(irc_t *irc, ConnContext *ctx)
+{
+ switch(ctx->otr_offer) {
+ case OFFER_NOT:
+ irc_usermsg(irc, " otr offer status: none sent");
+ break;
+ case OFFER_SENT:
+ irc_usermsg(irc, " otr offer status: awaiting reply");
+ break;
+ case OFFER_ACCEPTED:
+ irc_usermsg(irc, " otr offer status: accepted our offer");
+ break;
+ case OFFER_REJECTED:
+ irc_usermsg(irc, " otr offer status: ignored our offer");
+ break;
+ default:
+ irc_usermsg(irc, " otr offer status: %d", ctx->otr_offer);
+ }
+
+ switch(ctx->msgstate) {
+ case OTRL_MSGSTATE_PLAINTEXT:
+ irc_usermsg(irc, " connection state: cleartext");
+ break;
+ case OTRL_MSGSTATE_ENCRYPTED:
+ irc_usermsg(irc, " connection state: encrypted (v%d)", ctx->protocol_version);
+ break;
+ case OTRL_MSGSTATE_FINISHED:
+ irc_usermsg(irc, " connection state: shut down");
+ break;
+ default:
+ irc_usermsg(irc, " connection state: %d", ctx->msgstate);
+ }
+
+ irc_usermsg(irc, " known fingerprints: (bold=active)");
+ show_fingerprints(irc, ctx);
}
void otr_keygen(irc_t *irc, const char *handle, const char *protocol)