aboutsummaryrefslogtreecommitdiffstats
path: root/otr.c
diff options
context:
space:
mode:
Diffstat (limited to 'otr.c')
-rw-r--r--otr.c448
1 files changed, 270 insertions, 178 deletions
diff --git a/otr.c b/otr.c
index 1bea9c44..67e27474 100644
--- a/otr.c
+++ b/otr.c
@@ -7,7 +7,7 @@
/*
OTR support (cf. http://www.cypherpunks.ca/otr/)
- (c) 2008-2010 Sven Moritz Hallberg <pesco@khjk.org>
+ (c) 2008-2011 Sven Moritz Hallberg <pesco@khjk.org>
(c) 2008 funded by stonedcoder.org
files used to store OTR data:
@@ -162,6 +162,9 @@ void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs)
void otr_smp_or_smpq(irc_t *irc, const char *nick, const char *question,
const char *secret);
+/* update flags within the irc_user structure to reflect OTR status of context */
+void otr_update_uflags(ConnContext *context, irc_user_t *u);
+
/* update op/voice flag of given user according to encryption state and settings
returns 0 if neither op_buddies nor voice_buddies is set to "encrypted",
i.e. msgstate should be announced seperately */
@@ -182,6 +185,9 @@ 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);
+/* check whether a string is safe to use in a path component */
+int strsane(const char *s);
+
/* functions to be called for certain events */
static const struct irc_plugin otr_plugin;
@@ -236,6 +242,8 @@ gboolean otr_irc_new(irc_t *irc)
l = g_slist_prepend( l, "manual" );
l = g_slist_prepend( l, "always" );
s->eval_data = l;
+
+ s = set_add( &irc->b->set, "otr_does_html", "true", set_eval_bool, irc );
return TRUE;
}
@@ -269,15 +277,17 @@ void otr_load(irc_t *irc)
gcry_error_t enoent = gcry_error_from_errno(ENOENT);
int kg=0;
- g_snprintf(s, 511, "%s%s.otr_keys", global.conf->configdir, irc->user->nick);
- e = otrl_privkey_read(irc->otr->us, s);
- if(e && e!=enoent) {
- irc_usermsg(irc, "otr load: %s: %s", s, gcry_strerror(e));
- }
- g_snprintf(s, 511, "%s%s.otr_fprints", global.conf->configdir, irc->user->nick);
- e = otrl_privkey_read_fingerprints(irc->otr->us, s, NULL, NULL);
- if(e && e!=enoent) {
- irc_usermsg(irc, "otr load: %s: %s", s, gcry_strerror(e));
+ if(strsane(irc->user->nick)) {
+ g_snprintf(s, 511, "%s%s.otr_keys", global.conf->configdir, irc->user->nick);
+ e = otrl_privkey_read(irc->otr->us, s);
+ if(e && e!=enoent) {
+ irc_rootmsg(irc, "otr load: %s: %s", s, gcry_strerror(e));
+ }
+ g_snprintf(s, 511, "%s%s.otr_fprints", global.conf->configdir, irc->user->nick);
+ e = otrl_privkey_read_fingerprints(irc->otr->us, s, NULL, NULL);
+ if(e && e!=enoent) {
+ irc_rootmsg(irc, "otr load: %s: %s", s, gcry_strerror(e));
+ }
}
/* check for otr keys on all accounts */
@@ -285,7 +295,7 @@ void otr_load(irc_t *irc)
kg = otr_check_for_key(a) || kg;
}
if(kg) {
- irc_usermsg(irc, "Notice: "
+ irc_rootmsg(irc, "Notice: "
"The accounts above do not have OTR encryption keys associated with them, yet. "
"These keys are now being generated in the background. "
"You will be notified as they are completed. "
@@ -300,34 +310,40 @@ void otr_save(irc_t *irc)
char s[512];
gcry_error_t e;
- g_snprintf(s, 511, "%s%s.otr_fprints", global.conf->configdir, irc->user->nick);
- e = otrl_privkey_write_fingerprints(irc->otr->us, s);
- if(e) {
- irc_usermsg(irc, "otr save: %s: %s", s, gcry_strerror(e));
+ if(strsane(irc->user->nick)) {
+ g_snprintf(s, 511, "%s%s.otr_fprints", global.conf->configdir, irc->user->nick);
+ e = otrl_privkey_write_fingerprints(irc->otr->us, s);
+ if(e) {
+ irc_rootmsg(irc, "otr save: %s: %s", s, gcry_strerror(e));
+ }
+ chmod(s, 0600);
}
- chmod(s, 0600);
}
void otr_remove(const char *nick)
{
char s[512];
- g_snprintf(s, 511, "%s%s.otr_keys", global.conf->configdir, nick);
- unlink(s);
- g_snprintf(s, 511, "%s%s.otr_fprints", global.conf->configdir, nick);
- unlink(s);
+ if(strsane(nick)) {
+ g_snprintf(s, 511, "%s%s.otr_keys", global.conf->configdir, nick);
+ unlink(s);
+ g_snprintf(s, 511, "%s%s.otr_fprints", global.conf->configdir, nick);
+ unlink(s);
+ }
}
void otr_rename(const char *onick, const char *nnick)
{
char s[512], t[512];
- g_snprintf(s, 511, "%s%s.otr_keys", global.conf->configdir, onick);
- g_snprintf(t, 511, "%s%s.otr_keys", global.conf->configdir, nnick);
- rename(s,t);
- g_snprintf(s, 511, "%s%s.otr_fprints", global.conf->configdir, onick);
- g_snprintf(t, 511, "%s%s.otr_fprints", global.conf->configdir, nnick);
- rename(s,t);
+ if(strsane(nnick) && strsane(onick)) {
+ g_snprintf(s, 511, "%s%s.otr_keys", global.conf->configdir, onick);
+ g_snprintf(t, 511, "%s%s.otr_keys", global.conf->configdir, nnick);
+ rename(s,t);
+ g_snprintf(s, 511, "%s%s.otr_fprints", global.conf->configdir, onick);
+ g_snprintf(t, 511, "%s%s.otr_fprints", global.conf->configdir, nnick);
+ rename(s,t);
+ }
}
int otr_check_for_key(account_t *a)
@@ -342,13 +358,13 @@ int otr_check_for_key(account_t *a)
k = otrl_privkey_find(irc->otr->us, a->user, a->prpl->name);
if(k) {
- irc_usermsg(irc, "otr: %s/%s ready", a->user, a->prpl->name);
+ irc_rootmsg(irc, "otr: %s/%s ready", a->user, a->prpl->name);
return 0;
} if(keygen_in_progress(irc, a->user, a->prpl->name)) {
- irc_usermsg(irc, "otr: keygen for %s/%s already in progress", a->user, a->prpl->name);
+ irc_rootmsg(irc, "otr: keygen for %s/%s already in progress", a->user, a->prpl->name);
return 0;
} else {
- irc_usermsg(irc, "otr: starting background keygen for %s/%s", a->user, a->prpl->name);
+ irc_rootmsg(irc, "otr: starting background keygen for %s/%s", a->user, a->prpl->name);
otr_keygen(irc, a->user, a->prpl->name);
return 1;
}
@@ -359,7 +375,6 @@ char *otr_filter_msg_in(irc_user_t *iu, char *msg, int flags)
int ignore_msg;
char *newmsg = NULL;
OtrlTLV *tlvs = NULL;
- char *colormsg;
irc_t *irc = iu->irc;
struct im_connection *ic = iu->bu->ic;
@@ -379,33 +394,59 @@ char *otr_filter_msg_in(irc_user_t *iu, char *msg, int flags)
return NULL;
} else if(!newmsg) {
/* this was a non-OTR message */
- return g_strdup(msg);
+ return msg;
} else {
/* OTR has processed this message */
ConnContext *context = otrl_context_find(irc->otr->us, iu->bu->handle,
ic->acc->user, ic->acc->prpl->name, 0, NULL, NULL, NULL);
- if(context && context->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
- set_getbool(&ic->bee->set, "otr_color_encrypted")) {
- /* color according to f'print trust */
- int color;
- const char *trust = context->active_fingerprint->trust;
- if(trust && trust[0] != '\0')
- color=3; /* green */
- else
- color=5; /* red */
-
- if(newmsg[0] == ',') {
- /* could be a problem with the color code */
- /* insert a space between color spec and message */
- colormsg = g_strdup_printf("\x03%.2d %s\x0F", color, newmsg);
- } else {
- colormsg = g_strdup_printf("\x03%.2d%s\x0F", color, newmsg);
+
+ /* we're done with the original msg, which will be caller-freed. */
+ /* NB: must not change the newmsg pointer, since we free it. */
+ msg = newmsg;
+
+ if(context && context->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
+ /* HTML decoding */
+ /* perform any necessary stripping that the top level would miss */
+ if(set_getbool(&ic->bee->set, "otr_does_html") &&
+ !(ic->flags & OPT_DOES_HTML) &&
+ set_getbool(&ic->bee->set, "strip_html")) {
+ strip_html(msg);
}
- } else {
- colormsg = g_strdup(newmsg);
+
+ /* coloring */
+ if(set_getbool(&ic->bee->set, "otr_color_encrypted")) {
+ int color; /* color according to f'print trust */
+ char *pre="", *sep=""; /* optional parts */
+ const char *trust = context->active_fingerprint->trust;
+
+ if(trust && trust[0] != '\0')
+ color=3; /* green */
+ else
+ color=5; /* red */
+
+ /* in a query window, keep "/me " uncolored at the beginning */
+ if(g_strncasecmp(msg, "/me ", 4) == 0
+ && irc_user_msgdest(iu) == irc->user->nick) {
+ msg += 4; /* skip */
+ pre = "/me ";
+ }
+
+ /* comma in first place could mess with the color code */
+ if(msg[0] == ',') {
+ /* insert a space between color spec and message */
+ sep = " ";
+ }
+
+ msg = g_strdup_printf("%s\x03%.2d%s%s\x0F", pre,
+ color, sep, msg);
+ }
+ }
+
+ if(msg == newmsg) {
+ msg = g_strdup(newmsg);
}
otrl_message_free(newmsg);
- return colormsg;
+ return msg;
}
}
@@ -413,6 +454,7 @@ char *otr_filter_msg_out(irc_user_t *iu, char *msg, int flags)
{
int st;
char *otrmsg = NULL;
+ char *emsg = msg; /* the message as we hand it to libotr */
ConnContext *ctx = NULL;
irc_t *irc = iu->irc;
struct im_connection *ic = iu->bu->ic;
@@ -421,18 +463,29 @@ char *otr_filter_msg_out(irc_user_t *iu, char *msg, int flags)
if(ic->acc->prpl->options & OPT_NOOTR) {
return msg;
}
+
+ ctx = otrl_context_find(irc->otr->us,
+ iu->bu->handle, ic->acc->user, ic->acc->prpl->name,
+ 1, NULL, NULL, NULL);
+
+ /* HTML encoding */
+ /* consider OTR plaintext to be HTML if otr_does_html is set */
+ if(ctx && ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
+ set_getbool(&ic->bee->set, "otr_does_html") &&
+ (g_strncasecmp(msg, "<html>", 6) != 0)) {
+ emsg = escape_html(msg);
+ }
st = otrl_message_sending(irc->otr->us, &otr_ops, ic,
ic->acc->user, ic->acc->prpl->name, iu->bu->handle,
- msg, NULL, &otrmsg, NULL, NULL);
+ emsg, NULL, &otrmsg, NULL, NULL);
+ if(emsg != msg) {
+ g_free(emsg); /* we're done with this one */
+ }
if(st) {
return NULL;
}
- ctx = otrl_context_find(irc->otr->us,
- iu->bu->handle, ic->acc->user, ic->acc->prpl->name,
- 1, NULL, NULL, NULL);
-
if(otrmsg) {
if(!ctx) {
otrl_message_free(otrmsg);
@@ -479,13 +532,13 @@ static void cmd_otr(irc_t *irc, char **args)
}
if(!cmd->command) {
- irc_usermsg(irc, "%s: unknown subcommand \"%s\", see \x02help otr\x02",
+ irc_rootmsg(irc, "%s: unknown subcommand \"%s\", see \x02help otr\x02",
args[0], args[1]);
return;
}
if(!args[cmd->required_parameters+1]) {
- irc_usermsg(irc, "%s %s: not enough arguments (%d req.)",
+ irc_rootmsg(irc, "%s %s: not enough arguments (%d req.)",
args[0], args[1], cmd->required_parameters);
return;
}
@@ -557,7 +610,7 @@ void op_inject_message(void *opdata, const char *accountname,
if (strcmp(accountname, recipient) == 0) {
/* huh? injecting messages to myself? */
- irc_usermsg(irc, "note to self: %s", message);
+ irc_rootmsg(irc, "note to self: %s", message);
} else {
/* need to drop some consts here :-( */
/* TODO: get flags into op_inject_message?! */
@@ -572,9 +625,15 @@ int op_display_otr_message(void *opdata, const char *accountname,
struct im_connection *ic = check_imc(opdata, accountname, protocol);
char *msg = g_strdup(message);
irc_t *irc = ic->bee->ui_data;
+ irc_user_t *u = peeruser(irc, username, protocol);
strip_html(msg);
- irc_usermsg(irc, "otr: %s", msg);
+ if(u) {
+ /* display as a notice from this particular user */
+ irc_usernotice(u, "%s", msg);
+ } else {
+ irc_rootmsg(irc, "[otr] %s", msg);
+ }
g_free(msg);
return 0;
@@ -586,11 +645,17 @@ void op_new_fingerprint(void *opdata, OtrlUserState us,
{
struct im_connection *ic = check_imc(opdata, accountname, protocol);
irc_t *irc = ic->bee->ui_data;
+ irc_user_t *u = peeruser(irc, username, protocol);
char hunam[45]; /* anybody looking? ;-) */
otrl_privkey_hash_to_human(hunam, fingerprint);
- irc_usermsg(irc, "new fingerprint for %s: %s",
- peernick(irc, username, protocol), hunam);
+ if(u) {
+ irc_usernotice(u, "new fingerprint: %s", hunam);
+ } else {
+ /* this case shouldn't normally happen */
+ irc_rootmsg(irc, "new fingerprint for %s/%s: %s",
+ username, protocol, hunam);
+ }
}
void op_write_fingerprints(void *opdata)
@@ -607,7 +672,6 @@ void op_gone_secure(void *opdata, ConnContext *context)
check_imc(opdata, context->accountname, context->protocol);
irc_user_t *u;
irc_t *irc = ic->bee->ui_data;
- const char *trust;
u = peeruser(irc, context->username, context->protocol);
if(!u) {
@@ -617,13 +681,11 @@ void op_gone_secure(void *opdata, ConnContext *context)
return;
}
- trust = context->active_fingerprint->trust;
- if(trust && trust[0])
- u->flags |= IRC_USER_OTR_ENCRYPTED | IRC_USER_OTR_TRUSTED;
- else
- u->flags = ( u->flags & ~IRC_USER_OTR_TRUSTED ) | IRC_USER_OTR_ENCRYPTED;
- if(!otr_update_modeflags(irc, u))
- irc_usermsg(irc, "conversation with %s is now off the record", u->nick);
+ otr_update_uflags(context, u);
+ if(!otr_update_modeflags(irc, u)) {
+ char *trust = u->flags & IRC_USER_OTR_TRUSTED ? "trusted" : "untrusted!";
+ irc_usernotice(u, "conversation is now off the record (%s)", trust);
+ }
}
void op_gone_insecure(void *opdata, ConnContext *context)
@@ -640,9 +702,9 @@ void op_gone_insecure(void *opdata, ConnContext *context)
context->username, context->protocol, context->accountname);
return;
}
- u->flags &= ~( IRC_USER_OTR_ENCRYPTED | IRC_USER_OTR_TRUSTED );
+ otr_update_uflags(context, u);
if(!otr_update_modeflags(irc, u))
- irc_usermsg(irc, "conversation with %s is now in the clear", u->nick);
+ irc_usernotice(u, "conversation is now in cleartext");
}
void op_still_secure(void *opdata, ConnContext *context, int is_reply)
@@ -659,12 +721,12 @@ void op_still_secure(void *opdata, ConnContext *context, int is_reply)
context->username, context->protocol, context->accountname);
return;
}
- if(context->active_fingerprint->trust[0])
- u->flags |= IRC_USER_OTR_ENCRYPTED | IRC_USER_OTR_TRUSTED;
- else
- u->flags = ( u->flags & ~IRC_USER_OTR_TRUSTED ) | IRC_USER_OTR_ENCRYPTED;
- if(!otr_update_modeflags(irc, u))
- irc_usermsg(irc, "otr connection with %s has been refreshed", u->nick);
+
+ otr_update_uflags(context, u);
+ if(!otr_update_modeflags(irc, u)) {
+ char *trust = u->flags & IRC_USER_OTR_TRUSTED ? "trusted" : "untrusted!";
+ irc_usernotice(u, "otr connection has been refreshed (%s)", trust);
+ }
}
void op_log_message(void *opdata, const char *message)
@@ -707,7 +769,7 @@ void cmd_otr_disconnect(irc_t *irc, char **args)
u = irc_user_by_name(irc, args[1]);
if(!u || !u->bu || !u->bu->ic) {
- irc_usermsg(irc, "%s: unknown user", args[1]);
+ irc_rootmsg(irc, "%s: unknown user", args[1]);
return;
}
@@ -732,11 +794,11 @@ void cmd_otr_connect(irc_t *irc, char **args)
u = irc_user_by_name(irc, args[1]);
if(!u || !u->bu || !u->bu->ic) {
- irc_usermsg(irc, "%s: unknown user", args[1]);
+ irc_rootmsg(irc, "%s: unknown user", args[1]);
return;
}
if(!(u->bu->flags & BEE_USER_ONLINE)) {
- irc_usermsg(irc, "%s is offline", args[1]);
+ irc_rootmsg(irc, "%s is offline", args[1]);
return;
}
@@ -763,14 +825,14 @@ void cmd_otr_trust(irc_t *irc, char **args)
u = irc_user_by_name(irc, args[1]);
if(!u || !u->bu || !u->bu->ic) {
- irc_usermsg(irc, "%s: unknown user", args[1]);
+ irc_rootmsg(irc, "%s: unknown user", args[1]);
return;
}
ctx = otrl_context_find(irc->otr->us, u->bu->handle,
u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL);
if(!ctx) {
- irc_usermsg(irc, "%s: no otr context with user", args[1]);
+ irc_rootmsg(irc, "%s: no otr context with user", args[1]);
return;
}
@@ -782,18 +844,18 @@ void cmd_otr_trust(irc_t *irc, char **args)
int x, y;
if(!*p || !*q) {
- irc_usermsg(irc, "failed: truncated fingerprint block %d", i+1);
+ irc_rootmsg(irc, "failed: truncated fingerprint block %d", i+1);
return;
}
x = hexval(*p);
y = hexval(*q);
if(x<0) {
- irc_usermsg(irc, "failed: %d. hex digit of block %d out of range", 2*j+1, i+1);
+ irc_rootmsg(irc, "failed: %d. hex digit of block %d out of range", 2*j+1, i+1);
return;
}
if(y<0) {
- irc_usermsg(irc, "failed: %d. hex digit of block %d out of range", 2*j+2, i+1);
+ irc_rootmsg(irc, "failed: %d. hex digit of block %d out of range", 2*j+2, i+1);
return;
}
@@ -802,11 +864,11 @@ void cmd_otr_trust(irc_t *irc, char **args)
}
fp = otrl_context_find_fingerprint(ctx, raw, 0, NULL);
if(!fp) {
- irc_usermsg(irc, "failed: no such fingerprint for %s", args[1]);
+ irc_rootmsg(irc, "failed: no such fingerprint for %s", args[1]);
} else {
char *trust = args[7] ? args[7] : "affirmed";
otrl_context_set_trust(fp, trust);
- irc_usermsg(irc, "fingerprint match, trust set to \"%s\"", trust);
+ irc_rootmsg(irc, "fingerprint match, trust set to \"%s\"", trust);
if(u->flags & IRC_USER_OTR_ENCRYPTED)
u->flags |= IRC_USER_OTR_TRUSTED;
otr_update_modeflags(irc, u);
@@ -834,21 +896,21 @@ void cmd_otr_info(irc_t *irc, char **args)
handle = arg;
ctx = otrl_context_find(irc->otr->us, handle, myhandle, protocol, 0, NULL, NULL, NULL);
if(!ctx) {
- irc_usermsg(irc, "no such context");
+ irc_rootmsg(irc, "no such context");
g_free(arg);
return;
}
} else {
irc_user_t *u = irc_user_by_name(irc, args[1]);
if(!u || !u->bu || !u->bu->ic) {
- irc_usermsg(irc, "%s: unknown user", args[1]);
+ irc_rootmsg(irc, "%s: unknown user", args[1]);
g_free(arg);
return;
}
ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user,
u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL);
if(!ctx) {
- irc_usermsg(irc, "no otr context with %s", args[1]);
+ irc_rootmsg(irc, "no otr context with %s", args[1]);
g_free(arg);
return;
}
@@ -856,7 +918,7 @@ void cmd_otr_info(irc_t *irc, char **args)
/* 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],
+ irc_rootmsg(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);
@@ -871,19 +933,19 @@ void cmd_otr_keygen(irc_t *irc, char **args)
n = atoi(args[1]);
if(n<0 || (!n && strcmp(args[1], "0"))) {
- irc_usermsg(irc, "%s: invalid account number", args[1]);
+ irc_rootmsg(irc, "%s: invalid account number", args[1]);
return;
}
a = irc->b->accounts;
for(i=0; i<n && a; i++, a=a->next);
if(!a) {
- irc_usermsg(irc, "%s: no such account", args[1]);
+ irc_rootmsg(irc, "%s: no such account", args[1]);
return;
}
if(keygen_in_progress(irc, a->user, a->prpl->name)) {
- irc_usermsg(irc, "keygen for account %d already in progress", n);
+ irc_rootmsg(irc, "keygen for account %d already in progress", n);
return;
}
@@ -905,7 +967,7 @@ void yes_forget_fingerprint(void *data)
g_free(p);
if(fp == fp->context->active_fingerprint) {
- irc_usermsg(irc, "that fingerprint is active, terminate otr connection first");
+ irc_rootmsg(irc, "that fingerprint is active, terminate otr connection first");
return;
}
@@ -921,7 +983,7 @@ void yes_forget_context(void *data)
g_free(p);
if(ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
- irc_usermsg(irc, "active otr connection with %s, terminate it first",
+ irc_rootmsg(irc, "active otr connection with %s, terminate it first",
peernick(irc, ctx->username, ctx->protocol));
return;
}
@@ -953,21 +1015,21 @@ void cmd_otr_forget(irc_t *irc, char **args)
pair_t *p;
if(!args[3]) {
- irc_usermsg(irc, "otr %s %s: not enough arguments (2 req.)", args[0], args[1]);
+ irc_rootmsg(irc, "otr %s %s: not enough arguments (2 req.)", args[0], args[1]);
return;
}
/* TODO: allow context specs ("user/proto/account") in 'otr forget fingerprint'? */
u = irc_user_by_name(irc, args[2]);
if(!u || !u->bu || !u->bu->ic) {
- irc_usermsg(irc, "%s: unknown user", args[2]);
+ irc_rootmsg(irc, "%s: unknown user", args[2]);
return;
}
ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user,
u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL);
if(!ctx) {
- irc_usermsg(irc, "no otr context with %s", args[2]);
+ irc_rootmsg(irc, "no otr context with %s", args[2]);
return;
}
@@ -978,7 +1040,7 @@ void cmd_otr_forget(irc_t *irc, char **args)
}
if(fp == ctx->active_fingerprint) {
- irc_usermsg(irc, "that fingerprint is active, terminate otr connection first");
+ irc_rootmsg(irc, "that fingerprint is active, terminate otr connection first");
return;
}
@@ -1003,19 +1065,19 @@ void cmd_otr_forget(irc_t *irc, char **args)
/* TODO: allow context specs ("user/proto/account") in 'otr forget contex'? */
u = irc_user_by_name(irc, args[2]);
if(!u || !u->bu || !u->bu->ic) {
- irc_usermsg(irc, "%s: unknown user", args[2]);
+ irc_rootmsg(irc, "%s: unknown user", args[2]);
return;
}
ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user,
u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL);
if(!ctx) {
- irc_usermsg(irc, "no otr context with %s", args[2]);
+ irc_rootmsg(irc, "no otr context with %s", args[2]);
return;
}
if(ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
- irc_usermsg(irc, "active otr connection with %s, terminate it first", args[2]);
+ irc_rootmsg(irc, "active otr connection with %s, terminate it first", args[2]);
return;
}
@@ -1048,7 +1110,7 @@ void cmd_otr_forget(irc_t *irc, char **args)
else
{
- irc_usermsg(irc, "otr %s: unknown subcommand \"%s\", see \x02help otr forget\x02",
+ irc_rootmsg(irc, "otr %s: unknown subcommand \"%s\", see \x02help otr forget\x02",
args[0], args[1]);
}
}
@@ -1074,7 +1136,7 @@ void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs)
ic->acc->user, ic->acc->prpl->name, 1, NULL, NULL, NULL);
if(!context) {
/* huh? out of memory or what? */
- irc_usermsg(irc, "smp: failed to get otr context for %s", u->nick);
+ irc_rootmsg(irc, "smp: failed to get otr context for %s", u->nick);
otrl_message_abort_smp(us, ops, u->bu->ic, context);
otrl_sm_state_free(context->smstate);
return;
@@ -1082,7 +1144,7 @@ void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs)
nextMsg = context->smstate->nextExpected;
if (context->smstate->sm_prog_state == OTRL_SMP_PROG_CHEATED) {
- irc_usermsg(irc, "smp %s: opponent violated protocol, aborting",
+ irc_rootmsg(irc, "smp %s: opponent violated protocol, aborting",
u->nick);
otrl_message_abort_smp(us, ops, u->bu->ic, context);
otrl_sm_state_free(context->smstate);
@@ -1092,14 +1154,14 @@ void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs)
tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1Q);
if (tlv) {
if (nextMsg != OTRL_SMP_EXPECT1) {
- irc_usermsg(irc, "smp %s: spurious SMP1Q received, aborting", u->nick);
+ irc_rootmsg(irc, "smp %s: spurious SMP1Q received, aborting", u->nick);
otrl_message_abort_smp(us, ops, u->bu->ic, context);
otrl_sm_state_free(context->smstate);
} else {
char *question = g_strndup((char *)tlv->data, tlv->len);
- irc_usermsg(irc, "smp: initiated by %s with question: \x02\"%s\"\x02", u->nick,
+ irc_rootmsg(irc, "smp: initiated by %s with question: \x02\"%s\"\x02", u->nick,
question);
- irc_usermsg(irc, "smp: respond with \x02otr smp %s <answer>\x02",
+ irc_rootmsg(irc, "smp: respond with \x02otr smp %s <answer>\x02",
u->nick);
g_free(question);
/* smp stays in EXPECT1 until user responds */
@@ -1108,11 +1170,11 @@ void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs)
tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1);
if (tlv) {
if (nextMsg != OTRL_SMP_EXPECT1) {
- irc_usermsg(irc, "smp %s: spurious SMP1 received, aborting", u->nick);
+ irc_rootmsg(irc, "smp %s: spurious SMP1 received, aborting", u->nick);
otrl_message_abort_smp(us, ops, u->bu->ic, context);
otrl_sm_state_free(context->smstate);
} else {
- irc_usermsg(irc, "smp: initiated by %s"
+ irc_rootmsg(irc, "smp: initiated by %s"
" - respond with \x02otr smp %s <secret>\x02",
u->nick, u->nick);
/* smp stays in EXPECT1 until user responds */
@@ -1121,7 +1183,7 @@ void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs)
tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2);
if (tlv) {
if (nextMsg != OTRL_SMP_EXPECT2) {
- irc_usermsg(irc, "smp %s: spurious SMP2 received, aborting", u->nick);
+ irc_rootmsg(irc, "smp %s: spurious SMP2 received, aborting", u->nick);
otrl_message_abort_smp(us, ops, u->bu->ic, context);
otrl_sm_state_free(context->smstate);
} else {
@@ -1132,25 +1194,25 @@ void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs)
tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3);
if (tlv) {
if (nextMsg != OTRL_SMP_EXPECT3) {
- irc_usermsg(irc, "smp %s: spurious SMP3 received, aborting", u->nick);
+ irc_rootmsg(irc, "smp %s: spurious SMP3 received, aborting", u->nick);
otrl_message_abort_smp(us, ops, u->bu->ic, context);
otrl_sm_state_free(context->smstate);
} else {
/* SMP3 received, otrl_message_receiving will have sent SMP4 */
if(context->smstate->sm_prog_state == OTRL_SMP_PROG_SUCCEEDED) {
if(context->smstate->received_question) {
- irc_usermsg(irc, "smp %s: correct answer, you are trusted",
+ irc_rootmsg(irc, "smp %s: correct answer, you are trusted",
u->nick);
} else {
- irc_usermsg(irc, "smp %s: secrets proved equal, fingerprint trusted",
+ irc_rootmsg(irc, "smp %s: secrets proved equal, fingerprint trusted",
u->nick);
}
} else {
if(context->smstate->received_question) {
- irc_usermsg(irc, "smp %s: wrong answer, you are not trusted",
+ irc_rootmsg(irc, "smp %s: wrong answer, you are not trusted",
u->nick);
} else {
- irc_usermsg(irc, "smp %s: secrets did not match, fingerprint not trusted",
+ irc_rootmsg(irc, "smp %s: secrets did not match, fingerprint not trusted",
u->nick);
}
}
@@ -1161,16 +1223,16 @@ void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs)
tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4);
if (tlv) {
if (nextMsg != OTRL_SMP_EXPECT4) {
- irc_usermsg(irc, "smp %s: spurious SMP4 received, aborting", u->nick);
+ irc_rootmsg(irc, "smp %s: spurious SMP4 received, aborting", u->nick);
otrl_message_abort_smp(us, ops, u->bu->ic, context);
otrl_sm_state_free(context->smstate);
} else {
/* SMP4 received, otrl_message_receiving will have set fp trust */
if(context->smstate->sm_prog_state == OTRL_SMP_PROG_SUCCEEDED) {
- irc_usermsg(irc, "smp %s: secrets proved equal, fingerprint trusted",
+ irc_rootmsg(irc, "smp %s: secrets proved equal, fingerprint trusted",
u->nick);
} else {
- irc_usermsg(irc, "smp %s: secrets did not match, fingerprint not trusted",
+ irc_rootmsg(irc, "smp %s: secrets did not match, fingerprint not trusted",
u->nick);
}
otrl_sm_state_free(context->smstate);
@@ -1179,7 +1241,7 @@ void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs)
}
tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP_ABORT);
if (tlv) {
- irc_usermsg(irc, "smp: received abort from %s", u->nick);
+ irc_rootmsg(irc, "smp: received abort from %s", u->nick);
otrl_sm_state_free(context->smstate);
/* smp is in back in EXPECT1 */
}
@@ -1194,18 +1256,18 @@ void otr_smp_or_smpq(irc_t *irc, const char *nick, const char *question,
u = irc_user_by_name(irc, nick);
if(!u || !u->bu || !u->bu->ic) {
- irc_usermsg(irc, "%s: unknown user", nick);
+ irc_rootmsg(irc, "%s: unknown user", nick);
return;
}
if(!(u->bu->flags & BEE_USER_ONLINE)) {
- irc_usermsg(irc, "%s is offline", nick);
+ irc_rootmsg(irc, "%s is offline", nick);
return;
}
ctx = otrl_context_find(irc->otr->us, u->bu->handle,
u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL);
if(!ctx || ctx->msgstate != OTRL_MSGSTATE_ENCRYPTED) {
- irc_usermsg(irc, "smp: otr inactive with %s, try \x02otr connect"
+ irc_rootmsg(irc, "smp: otr inactive with %s, try \x02otr connect"
" %s\x02", nick, nick);
return;
}
@@ -1220,7 +1282,7 @@ void otr_smp_or_smpq(irc_t *irc, const char *nick, const char *question,
if(question) {
/* this was 'otr smpq', just initiate */
- irc_usermsg(irc, "smp: initiating with %s...", u->nick);
+ irc_rootmsg(irc, "smp: initiating with %s...", u->nick);
otrl_message_initiate_smp_q(irc->otr->us, &otr_ops, u->bu->ic, ctx,
question, (unsigned char *)secret, strlen(secret));
/* smp is now in EXPECT2 */
@@ -1229,14 +1291,14 @@ void otr_smp_or_smpq(irc_t *irc, const char *nick, const char *question,
/* warning: the following assumes that smstates are cleared whenever an SMP
is completed or aborted! */
if(ctx->smstate->secret == NULL) {
- irc_usermsg(irc, "smp: initiating with %s...", u->nick);
+ irc_rootmsg(irc, "smp: initiating with %s...", u->nick);
otrl_message_initiate_smp(irc->otr->us, &otr_ops,
u->bu->ic, ctx, (unsigned char *)secret, strlen(secret));
/* smp is now in EXPECT2 */
} else {
/* if we're still in EXPECT1 but smstate is initialized, we must have
received the SMP1, so let's issue a response */
- irc_usermsg(irc, "smp: responding to %s...", u->nick);
+ irc_rootmsg(irc, "smp: responding to %s...", u->nick);
otrl_message_respond_smp(irc->otr->us, &otr_ops,
u->bu->ic, ctx, (unsigned char *)secret, strlen(secret));
/* smp is now in EXPECT3 */
@@ -1311,9 +1373,26 @@ const char *peernick(irc_t *irc, const char *handle, const char *protocol)
}
}
+void otr_update_uflags(ConnContext *context, irc_user_t *u)
+{
+ const char *trust;
+
+ if(context->active_fingerprint) {
+ u->flags |= IRC_USER_OTR_ENCRYPTED;
+
+ trust = context->active_fingerprint->trust;
+ if(trust && trust[0])
+ u->flags |= IRC_USER_OTR_TRUSTED;
+ else
+ u->flags &= ~IRC_USER_OTR_TRUSTED;
+ } else {
+ u->flags &= ~IRC_USER_OTR_ENCRYPTED;
+ }
+}
+
int otr_update_modeflags(irc_t *irc, irc_user_t *u)
{
- return 1;
+ return 0;
}
void show_fingerprints(irc_t *irc, ConnContext *ctx)
@@ -1334,13 +1413,13 @@ 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_rootmsg(irc, " \x02%s (%s)\x02", human, trust);
} else {
- irc_usermsg(irc, " %s (%s)", human, trust);
+ irc_rootmsg(irc, " %s (%s)", human, trust);
}
}
if(count==0)
- irc_usermsg(irc, " (none)");
+ irc_rootmsg(irc, " (none)");
}
Fingerprint *match_fingerprint(irc_t *irc, ConnContext *ctx, const char **args)
@@ -1359,14 +1438,14 @@ Fingerprint *match_fingerprint(irc_t *irc, ConnContext *ctx, const char **args)
char c = toupper(args[i][j]);
if(n>=40) {
- irc_usermsg(irc, "too many fingerprint digits given, expected at most 40");
+ irc_rootmsg(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);
+ irc_rootmsg(irc, "invalid hex digit '%c' in block %d", args[i][j], i+1);
return NULL;
}
@@ -1387,7 +1466,7 @@ Fingerprint *match_fingerprint(irc_t *irc, ConnContext *ctx, const char **args)
break;
}
if(!fp) {
- irc_usermsg(irc, "%s: no match", prefix);
+ irc_rootmsg(irc, "%s: no match", prefix);
return NULL;
}
@@ -1400,7 +1479,7 @@ Fingerprint *match_fingerprint(irc_t *irc, ConnContext *ctx, const char **args)
break;
}
if(fp2) {
- irc_usermsg(irc, "%s: multiple matches", prefix);
+ irc_rootmsg(irc, "%s: multiple matches", prefix);
return NULL;
}
@@ -1423,14 +1502,14 @@ OtrlPrivKey *match_privkey(irc_t *irc, const char **args)
char c = toupper(args[i][j]);
if(n>=40) {
- irc_usermsg(irc, "too many fingerprint digits given, expected at most 40");
+ irc_rootmsg(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);
+ irc_rootmsg(irc, "invalid hex digit '%c' in block %d", args[i][j], i+1);
return NULL;
}
@@ -1451,7 +1530,7 @@ OtrlPrivKey *match_privkey(irc_t *irc, const char **args)
break;
}
if(!k) {
- irc_usermsg(irc, "%s: no match", prefix);
+ irc_rootmsg(irc, "%s: no match", prefix);
return NULL;
}
@@ -1464,7 +1543,7 @@ OtrlPrivKey *match_privkey(irc_t *irc, const char **args)
break;
}
if(k2) {
- irc_usermsg(irc, "%s: multiple matches", prefix);
+ irc_rootmsg(irc, "%s: multiple matches", prefix);
return NULL;
}
@@ -1479,16 +1558,16 @@ void show_general_otr_info(irc_t *irc)
kg_t *kg;
/* list all privkeys (including ones being generated) */
- irc_usermsg(irc, "\x1fprivate keys:\x1f");
+ irc_rootmsg(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);
+ irc_rootmsg(irc, " %s/%s - DSA", key->accountname, key->protocol);
break;
default:
- irc_usermsg(irc, " %s/%s - type %d", key->accountname, key->protocol,
+ irc_rootmsg(irc, " %s/%s - type %d", key->accountname, key->protocol,
key->pubkey_type);
}
@@ -1497,25 +1576,25 @@ void show_general_otr_info(irc_t *irc)
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);
+ irc_rootmsg(irc, " %s", human);
}
if(irc->otr->sent_accountname) {
- irc_usermsg(irc, " %s/%s - DSA", irc->otr->sent_accountname,
+ irc_rootmsg(irc, " %s/%s - DSA", irc->otr->sent_accountname,
irc->otr->sent_protocol);
- irc_usermsg(irc, " (being generated)");
+ irc_rootmsg(irc, " (being generated)");
}
for(kg=irc->otr->todo; kg; kg=kg->next) {
- irc_usermsg(irc, " %s/%s - DSA", kg->accountname, kg->protocol);
- irc_usermsg(irc, " (queued)");
+ irc_rootmsg(irc, " %s/%s - DSA", kg->accountname, kg->protocol);
+ irc_rootmsg(irc, " (queued)");
}
if(key == irc->otr->us->privkey_root &&
!irc->otr->sent_accountname &&
kg == irc->otr->todo)
- irc_usermsg(irc, " (none)");
+ irc_rootmsg(irc, " (none)");
/* list all contexts */
- irc_usermsg(irc, "%s", "");
- irc_usermsg(irc, "\x1f" "connection contexts:\x1f (bold=currently encrypted)");
+ irc_rootmsg(irc, "%s", "");
+ irc_rootmsg(irc, "\x1f" "connection contexts:\x1f (bold=currently encrypted)");
for(ctx=irc->otr->us->context_root; ctx; ctx=ctx->next) {\
irc_user_t *u;
char *userstring;
@@ -1529,51 +1608,51 @@ void show_general_otr_info(irc_t *irc)
ctx->username, ctx->protocol, ctx->accountname);
if(ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
- irc_usermsg(irc, " \x02%s\x02", userstring);
+ irc_rootmsg(irc, " \x02%s\x02", userstring);
} else {
- irc_usermsg(irc, " %s", userstring);
+ irc_rootmsg(irc, " %s", userstring);
}
g_free(userstring);
}
if(ctx == irc->otr->us->context_root)
- irc_usermsg(irc, " (none)");
+ irc_rootmsg(irc, " (none)");
}
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");
+ irc_rootmsg(irc, " otr offer status: none sent");
break;
case OFFER_SENT:
- irc_usermsg(irc, " otr offer status: awaiting reply");
+ irc_rootmsg(irc, " otr offer status: awaiting reply");
break;
case OFFER_ACCEPTED:
- irc_usermsg(irc, " otr offer status: accepted our offer");
+ irc_rootmsg(irc, " otr offer status: accepted our offer");
break;
case OFFER_REJECTED:
- irc_usermsg(irc, " otr offer status: ignored our offer");
+ irc_rootmsg(irc, " otr offer status: ignored our offer");
break;
default:
- irc_usermsg(irc, " otr offer status: %d", ctx->otr_offer);
+ irc_rootmsg(irc, " otr offer status: %d", ctx->otr_offer);
}
switch(ctx->msgstate) {
case OTRL_MSGSTATE_PLAINTEXT:
- irc_usermsg(irc, " connection state: cleartext");
+ irc_rootmsg(irc, " connection state: cleartext");
break;
case OTRL_MSGSTATE_ENCRYPTED:
- irc_usermsg(irc, " connection state: encrypted (v%d)", ctx->protocol_version);
+ irc_rootmsg(irc, " connection state: encrypted (v%d)", ctx->protocol_version);
break;
case OTRL_MSGSTATE_FINISHED:
- irc_usermsg(irc, " connection state: shut down");
+ irc_rootmsg(irc, " connection state: shut down");
break;
default:
- irc_usermsg(irc, " connection state: %d", ctx->msgstate);
+ irc_rootmsg(irc, " connection state: %d", ctx->msgstate);
}
- irc_usermsg(irc, " fingerprints: (bold=active)");
+ irc_rootmsg(irc, " fingerprints: (bold=active)");
show_fingerprints(irc, ctx);
}
@@ -1613,20 +1692,20 @@ void otr_keygen(irc_t *irc, const char *handle, const char *protocol)
FILE *tof, *fromf;
if(pipe(to) < 0 || pipe(from) < 0) {
- irc_usermsg(irc, "otr keygen: couldn't create pipe: %s", strerror(errno));
+ irc_rootmsg(irc, "otr keygen: couldn't create pipe: %s", strerror(errno));
return;
}
tof = fdopen(to[1], "w");
fromf = fdopen(from[0], "r");
if(!tof || !fromf) {
- irc_usermsg(irc, "otr keygen: couldn't streamify pipe: %s", strerror(errno));
+ irc_rootmsg(irc, "otr keygen: couldn't streamify pipe: %s", strerror(errno));
return;
}
p = fork();
if(p<0) {
- irc_usermsg(irc, "otr keygen: couldn't fork: %s", strerror(errno));
+ irc_rootmsg(irc, "otr keygen: couldn't fork: %s", strerror(errno));
return;
}
@@ -1706,16 +1785,21 @@ gboolean keygen_finish_handler(gpointer data, gint fd, b_input_condition cond)
myfgets(filename, 512, irc->otr->from);
myfgets(msg, 512, irc->otr->from);
- irc_usermsg(irc, "%s", msg);
+ irc_rootmsg(irc, "%s", msg);
if(filename[0]) {
- char *kf = g_strdup_printf("%s%s.otr_keys", global.conf->configdir, irc->user->nick);
- char *tmp = g_strdup_printf("%s.new", kf);
- copyfile(filename, tmp);
- unlink(filename);
- rename(tmp,kf);
- otrl_privkey_read(irc->otr->us, kf);
- g_free(kf);
- g_free(tmp);
+ if(strsane(irc->user->nick)) {
+ char *kf = g_strdup_printf("%s%s.otr_keys", global.conf->configdir, irc->user->nick);
+ char *tmp = g_strdup_printf("%s.new", kf);
+ copyfile(filename, tmp);
+ unlink(filename);
+ rename(tmp,kf);
+ otrl_privkey_read(irc->otr->us, kf);
+ g_free(kf);
+ g_free(tmp);
+ } else {
+ otrl_privkey_read(irc->otr->us, filename);
+ unlink(filename);
+ }
}
/* forget this job */
@@ -1780,12 +1864,20 @@ void yes_keygen(void *data)
irc_t *irc = acc->bee->ui_data;
if(keygen_in_progress(irc, acc->user, acc->prpl->name)) {
- irc_usermsg(irc, "keygen for %s/%s already in progress",
+ irc_rootmsg(irc, "keygen for %s/%s already in progress",
acc->user, acc->prpl->name);
} else {
- irc_usermsg(irc, "starting background keygen for %s/%s",
+ irc_rootmsg(irc, "starting background keygen for %s/%s",
acc->user, acc->prpl->name);
- irc_usermsg(irc, "you will be notified when it completes");
+ irc_rootmsg(irc, "you will be notified when it completes");
otr_keygen(irc, acc->user, acc->prpl->name);
}
}
+
+/* check whether a string is safe to use in a path component */
+int strsane(const char *s)
+{
+ return strpbrk(s, "/\\") == NULL;
+}
+
+/* vim: set noet ts=4 sw=4: */