diff options
Diffstat (limited to 'otr.c')
| -rw-r--r-- | otr.c | 448 | 
1 files changed, 270 insertions, 178 deletions
| @@ -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: */ | 
