aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--irc.c25
-rw-r--r--irc.h2
-rw-r--r--lib/misc.c12
-rw-r--r--otr.c286
-rw-r--r--protocols/jabber/jabber.c1
-rw-r--r--protocols/msn/msn.c1
-rw-r--r--protocols/nogaim.c17
-rw-r--r--protocols/nogaim.h4
-rw-r--r--protocols/oscar/oscar.c1
-rw-r--r--protocols/yahoo/yahoo.c1
-rw-r--r--set.c145
-rw-r--r--set.h5
-rw-r--r--user.h1
13 files changed, 420 insertions, 81 deletions
diff --git a/irc.c b/irc.c
index db681175..279401d0 100644
--- a/irc.c
+++ b/irc.c
@@ -101,8 +101,7 @@ irc_t *irc_new( int fd )
irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost, "BitlBee-IRCd initialized, please go on" );
irc_connection_list = g_slist_append( irc_connection_list, irc );
-
- set_add( &irc->set, "away_devoice", "true", set_eval_away_devoice, irc );
+
set_add( &irc->set, "auto_connect", "true", set_eval_bool, irc );
set_add( &irc->set, "auto_reconnect", "false", set_eval_bool, irc );
set_add( &irc->set, "auto_reconnect_delay", "300", set_eval_int, irc );
@@ -114,7 +113,9 @@ irc_t *irc_new( int fd )
set_add( &irc->set, "display_namechanges", "false", set_eval_bool, irc );
set_add( &irc->set, "handle_unknown", "root", NULL, irc );
set_add( &irc->set, "lcnicks", "true", set_eval_bool, irc );
- set_add( &irc->set, "ops", "both", set_eval_ops, irc );
+ set_add( &irc->set, "op_buddies", "false", 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 );
set_add( &irc->set, "private", "true", set_eval_bool, irc );
set_add( &irc->set, "query_order", "lifo", NULL, irc );
@@ -123,6 +124,7 @@ irc_t *irc_new( int fd )
set_add( &irc->set, "strip_html", "true", NULL, irc );
set_add( &irc->set, "to_char", ": ", set_eval_to_char, irc );
set_add( &irc->set, "typing_notice", "false", set_eval_bool, irc );
+ set_add( &irc->set, "voice_buddies", "notaway", set_eval_voice_buddies, irc );
conf_loaddefaults( irc );
@@ -642,7 +644,8 @@ void irc_names( irc_t *irc, char *channel )
user_t *u;
char namelist[385] = "";
struct groupchat *c = NULL;
- char *ops = set_getstr( &irc->set, "ops" );
+ char *oo = set_getstr(&irc->set, "op_buddies");
+ char *vo = set_getstr(&irc->set, "voice_buddies");
/* RFCs say there is no error reply allowed on NAMES, so when the
channel is invalid, just give an empty reply. */
@@ -657,10 +660,13 @@ void irc_names( irc_t *irc, char *channel )
*namelist = 0;
}
- if( u->ic && !u->away && set_getbool( &irc->set, "away_devoice" ) )
+ if( u->ic && !u->away && !strcmp(vo, "notaway") )
strcat( namelist, "+" );
- else if( ( strcmp( u->nick, irc->mynick ) == 0 && ( strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) == 0 ) ) ||
- ( strcmp( u->nick, irc->nick ) == 0 && ( strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) == 0 ) ) )
+ else if( ( strcmp( u->nick, irc->mynick ) == 0 && set_getbool(&irc->set, "op_root") ) ||
+ ( strcmp( u->nick, irc->nick ) == 0 && set_getbool(&irc->set, "op_user") ) ||
+ ( !u->away && !strcmp(oo, "notaway") ) ||
+ ( u->encrypted>1 && !strcmp(oo, "trusted") ) ||
+ ( u->encrypted && !strcmp(oo, "encrypted") ) )
strcat( namelist, "@" );
strcat( namelist, u->nick );
@@ -673,9 +679,10 @@ void irc_names( irc_t *irc, char *channel )
/* root and the user aren't in the channel userlist but should
show up in /NAMES, so list them first: */
- sprintf( namelist, "%s%s %s%s ", strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->mynick,
- strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->nick );
+ sprintf( namelist, "%s%s %s%s ", set_getbool(&irc->set, "op_root") ? "@" : "", irc->mynick,
+ set_getbool(&irc->set, "op_user") ? "@" : "", irc->nick );
+ /* TODO: Honor op/voice_buddies in chats?! */
for( l = c->in_room; l; l = l->next ) if( ( u = user_findhandle( c->ic, l->data ) ) )
{
if( strlen( namelist ) + strlen( u->nick ) > sizeof( namelist ) - 4 )
diff --git a/irc.h b/irc.h
index 318e263e..77738640 100644
--- a/irc.h
+++ b/irc.h
@@ -29,7 +29,7 @@
#include "otr.h"
#define IRC_MAX_LINE 512
-#define IRC_MAX_ARGS 8
+#define IRC_MAX_ARGS 16
#define IRC_LOGIN_TIMEOUT 60
#define IRC_PING_STRING "PinglBee"
diff --git a/lib/misc.c b/lib/misc.c
index 18d98f9e..a8df2354 100644
--- a/lib/misc.c
+++ b/lib/misc.c
@@ -142,6 +142,7 @@ void strip_html( char *in )
char *out = g_malloc( strlen( in ) + 1 );
char *s = out, *cs;
int i, matched;
+ int taglen;
memset( out, 0, strlen( in ) + 1 );
@@ -158,9 +159,18 @@ void strip_html( char *in )
while( *in && *in != '>' )
in ++;
+ taglen = in-cs-1; /* not <0 because the above loop runs at least once */
if( *in )
{
- if( g_strncasecmp( cs+1, "br", 2) == 0 )
+ if( g_strncasecmp( cs+1, "b", taglen) == 0 )
+ *(s++) = '\x02';
+ else if( g_strncasecmp( cs+1, "/b", taglen) == 0 )
+ *(s++) = '\x02';
+ else if( g_strncasecmp( cs+1, "i", taglen) == 0 )
+ *(s++) = '\x1f';
+ else if( g_strncasecmp( cs+1, "/i", taglen) == 0 )
+ *(s++) = '\x1f';
+ else if( g_strncasecmp( cs+1, "br", 2) == 0 )
*(s++) = '\n';
in ++;
}
diff --git a/otr.c b/otr.c
index 78952699..60581ee6 100644
--- a/otr.c
+++ b/otr.c
@@ -34,8 +34,6 @@ void op_write_fingerprints(void *opdata);
void op_gone_secure(void *opdata, ConnContext *context);
-void op_gone_secure(void *opdata, ConnContext *context);
-
void op_gone_insecure(void *opdata, ConnContext *context);
void op_still_secure(void *opdata, ConnContext *context, int is_reply);
@@ -52,7 +50,8 @@ const char *op_account_name(void *opdata, const char *account, const char *proto
/* 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_auth(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);
@@ -61,7 +60,8 @@ void cmd_otr_policy(irc_t *irc, char **args);
const command_t otr_commands[] = {
{ "abort", 1, &cmd_otr_abort, 0 },
{ "request", 1, &cmd_otr_request, 0 },
- { "auth", 2, &cmd_otr_auth, 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 },
@@ -96,12 +96,22 @@ void no_keygen(gpointer w, void *data);
struct im_connection *check_imc(void *opdata, const char *accountname,
const char *protocol);
-/* determine the nick for a given handle/protocol pair */
+/* determine the nick for a given handle/protocol pair
+ returns "handle/protocol" if not found */
const char *peernick(irc_t *irc, const char *handle, const char *protocol);
+/* 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);
+
/* handle SMP TLVs from a received message */
void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs);
+/* 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 */
+int otr_update_modeflags(irc_t *irc, user_t *u);
+
/* show the list of fingerprints associated with a given context */
void show_fingerprints(irc_t *irc, ConnContext *ctx);
@@ -238,8 +248,15 @@ char *otr_handle_message(struct im_connection *ic, const char *handle, const cha
char *colormsg;
if(!g_mutex_trylock(ic->irc->otr_mutex)) {
- /* TODO: queue msgs received during keygen for later */
- irc_usermsg(ic->irc, "msg from %s during keygen - dropped",
+ user_t *u = user_findhandle(ic, handle);
+
+ /* fallback for non-otr clients */
+ if(u && !u->encrypted) {
+ return g_strdup(msg);
+ }
+
+ /* TODO: queue msgs received during keygen for later? */
+ irc_usermsg(ic->irc, "otr msg from %s during keygen - dropped",
peernick(ic->irc, handle, ic->acc->prpl->name));
return NULL;
}
@@ -282,14 +299,24 @@ char *otr_handle_message(struct im_connection *ic, const char *handle, const cha
int otr_send_message(struct im_connection *ic, const char *handle, const char *msg, int flags)
{
- int st;
- char *otrmsg = NULL;
- ConnContext *ctx = NULL;
-
+ int st;
+ char *otrmsg = NULL;
+ ConnContext *ctx = NULL;
+
if(!g_mutex_trylock(ic->irc->otr_mutex)) {
- irc_usermsg(ic->irc, "msg to %s during keygen - not sent",
- peernick(ic->irc, handle, ic->acc->prpl->name));
- return 1;
+ user_t *u = user_findhandle(ic, handle);
+
+ /* Fallback for non-otr clients.
+ Yes, we must be very sure this doesn't send stuff in the clear where it
+ shouldn't... */
+ if(u && !u->encrypted) {
+ return ic->acc->prpl->buddy_msg(ic, (char *)handle, (char *)msg, flags);
+ }
+
+ /* otherwise refuse to send */
+ irc_usermsg(ic->irc, "otr msg to %s not sent during keygen",
+ peernick(ic->irc, handle, ic->acc->prpl->name));
+ return 1;
}
st = otrl_message_sending(ic->irc->otr_us, &global.otr_ops, ic,
@@ -413,14 +440,17 @@ void op_inject_message(void *opdata, const char *accountname,
}
int op_display_otr_message(void *opdata, const char *accountname,
- const char *protocol, const char *username, const char *msg)
+ const char *protocol, const char *username, const char *message)
{
struct im_connection *ic = check_imc(opdata, accountname, protocol);
+ char *msg = g_strdup(message);
- log_message(LOGLVL_DEBUG, "op_display_otr_message '%s' '%s' '%s' '%s'", accountname, protocol, username, msg);
+ log_message(LOGLVL_DEBUG, "op_display_otr_message '%s' '%s' '%s' '%s'", accountname, protocol, username, message);
- irc_usermsg(ic->irc, "%s", msg);
+ strip_html(msg);
+ irc_usermsg(ic->irc, "otr: %s", msg);
+ g_free(msg);
return 0;
}
@@ -451,51 +481,84 @@ void op_gone_secure(void *opdata, ConnContext *context)
{
struct im_connection *ic =
check_imc(opdata, context->accountname, context->protocol);
+ user_t *u;
log_message(LOGLVL_DEBUG, "op_gone_secure '%s' '%s' '%s'", context->accountname, context->protocol, context->username);
- irc_usermsg(ic->irc, "conversation with %s is now off the record",
- peernick(ic->irc, context->username, context->protocol));
+ 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);
+ return;
+ }
+ if(context->active_fingerprint->trust[0])
+ u->encrypted = 2;
+ else
+ u->encrypted = 1;
+ if(!otr_update_modeflags(ic->irc, u))
+ irc_usermsg(ic->irc, "conversation with %s is now off the record", u->nick);
}
void op_gone_insecure(void *opdata, ConnContext *context)
{
struct im_connection *ic =
check_imc(opdata, context->accountname, context->protocol);
+ user_t *u;
log_message(LOGLVL_DEBUG, "op_gone_insecure '%s' '%s' '%s'", context->accountname, context->protocol, context->username);
- irc_usermsg(ic->irc, "conversation with %s is now in the clear",
- peernick(ic->irc, context->username, context->protocol));
+ 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);
+ return;
+ }
+ u->encrypted = 0;
+ if(!otr_update_modeflags(ic->irc, u))
+ irc_usermsg(ic->irc, "conversation with %s is now in the clear", u->nick);
}
void op_still_secure(void *opdata, ConnContext *context, int is_reply)
{
struct im_connection *ic =
check_imc(opdata, context->accountname, context->protocol);
+ user_t *u;
log_message(LOGLVL_DEBUG, "op_still_secure '%s' '%s' '%s' is_reply=%d",
context->accountname, context->protocol, context->username, is_reply);
- irc_usermsg(ic->irc, "otr connection with %s has been refreshed",
- peernick(ic->irc, context->username, context->protocol));
+ 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);
+ return;
+ }
+ if(context->active_fingerprint->trust[0])
+ u->encrypted = 2;
+ else
+ u->encrypted = 1;
+ if(!otr_update_modeflags(ic->irc, u))
+ irc_usermsg(ic->irc, "otr connection with %s has been refreshed", u->nick);
}
void op_log_message(void *opdata, const char *message)
{
- log_message(LOGLVL_INFO, "%s", message);
+ char *msg = g_strdup(message);
+
+ strip_html(msg);
+ log_message(LOGLVL_INFO, "otr: %s", msg);
+ g_free(msg);
}
int op_max_message_size(void *opdata, ConnContext *context)
{
- /* TODO: make max_message_size a property of the prpl.
- the values here are taken from the libotr UPGRADING file */
- if(!strcmp(context->protocol, "msn"))
- return 1409;
- if(!strcmp(context->protocol, "yahoo"))
- return 832;
- if(!strcmp(context->protocol, "oscar"))
- return 2343;
+ struct im_connection *ic =
+ check_imc(opdata, context->accountname, context->protocol);
+
+ return ic->acc->prpl->mms;
}
const char *op_account_name(void *opdata, const char *account, const char *protocol)
@@ -541,7 +604,7 @@ void cmd_otr_request(irc_t *irc, char **args)
imc_buddy_msg(u->ic, u->handle, "?OTR?", 0);
}
-void cmd_otr_auth(irc_t *irc, char **args)
+void cmd_otr_smp(irc_t *irc, char **args)
{
user_t *u;
ConnContext *ctx;
@@ -588,6 +651,80 @@ void cmd_otr_auth(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;
+ ConnContext *ctx;
+ unsigned char raw[20];
+ Fingerprint *fp;
+ int i,j;
+
+ 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, "%s: no otr context with user", args[1]);
+ return;
+ }
+
+ /* convert given fingerprint to raw representation */
+ for(i=0; i<5; i++) {
+ for(j=0; j<4; j++) {
+ char *p = args[2+i]+(2*j);
+ char *q = p+1;
+ int x, y;
+
+ if(!*p || !*q) {
+ irc_usermsg(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);
+ return;
+ }
+ if(y<0) {
+ irc_usermsg(irc, "failed: %d. hex digit of block %d out of range", 2*j+2, i+1);
+ return;
+ }
+
+ raw[i*4+j] = x*16 + y;
+ }
+ }
+ fp = otrl_context_find_fingerprint(ctx, raw, 0, NULL);
+ if(!fp) {
+ irc_usermsg(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);
+ if(u->encrypted)
+ u->encrypted = 2;
+ otr_update_modeflags(irc, u);
+ }
+}
+
void cmd_otr_fprints(irc_t *irc, char **args)
{
if(args[1]) {
@@ -648,7 +785,7 @@ void cmd_otr_info(irc_t *irc, char **args)
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 info on %s", args[1]);
+ irc_usermsg(irc, "no otr context with %s", args[1]);
return;
}
@@ -671,18 +808,21 @@ void cmd_otr_info(irc_t *irc, char **args)
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);
- irc_usermsg(irc, " protocol version: %d", ctx->protocol_version);
- fp = ctx->active_fingerprint;
- if(!fp) {
- irc_usermsg(irc, " active f'print: none");
- } else {
- otrl_privkey_hash_to_human(human, fp->fingerprint);
- if(!fp->trust || fp->trust[0] == '\0') {
- trust="untrusted";
+
+ 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?");
} else {
- trust=fp->trust;
+ otrl_privkey_hash_to_human(human, fp->fingerprint);
+ if(!fp->trust || fp->trust[0] == '\0') {
+ trust="untrusted";
+ } else {
+ trust=fp->trust;
+ }
+ irc_usermsg(irc, " active f'print: %s (%s)", human, trust);
}
- irc_usermsg(irc, " active f'print: %s (%s)", human, trust);
}
}
@@ -808,12 +948,10 @@ struct im_connection *check_imc(void *opdata, const char *accountname,
return ic;
}
-const char *peernick(irc_t *irc, const char *handle, const char *protocol)
+user_t *peeruser(irc_t *irc, const char *handle, const char *protocol)
{
user_t *u;
- static char fallback[512];
- g_snprintf(fallback, 511, "%s/%s", handle, protocol);
for(u=irc->users; u; u=u->next) {
struct prpl *prpl;
if(!u->ic || !u->handle)
@@ -821,11 +959,55 @@ const char *peernick(irc_t *irc, const char *handle, const char *protocol)
prpl = u->ic->acc->prpl;
if(strcmp(prpl->name, protocol) == 0
&& prpl->handle_cmp(u->handle, handle) == 0) {
- return u->nick;
+ return u;
}
}
- return fallback;
+ return NULL;
+}
+
+const char *peernick(irc_t *irc, const char *handle, const char *protocol)
+{
+ static char fallback[512];
+
+ user_t *u = peeruser(irc, handle, protocol);
+ if(u) {
+ return u->nick;
+ } else {
+ g_snprintf(fallback, 511, "%s/%s", handle, protocol);
+ return fallback;
+ }
+}
+
+int otr_update_modeflags(irc_t *irc, user_t *u)
+{
+ char *vo = set_getstr(&irc->set, "voice_buddies");
+ char *oo = set_getstr(&irc->set, "op_buddies");
+ char eflag=0, tflag=0;
+ int e = u->encrypted;
+ int t = (u->encrypted > 1);
+
+ if(!strcmp(vo, "encrypted"))
+ eflag='v';
+ else if(!strcmp(oo, "encrypted"))
+ eflag='o';
+ if(!strcmp(vo, "trusted"))
+ tflag='v';
+ else if(!strcmp(oo, "trusted"))
+ tflag='o';
+
+ if(!eflag)
+ return 0;
+
+ if(tflag) {
+ irc_write( irc, ":%s!%s@%s MODE %s %c%c%c%c %s %s", irc->mynick, irc->mynick, irc->myhost,
+ irc->channel, e?'+':'-', eflag, t?'+':'-', tflag, u->nick, u->nick );
+ } else {
+ irc_write( irc, ":%s!%s@%s MODE %s %c%c %s", irc->mynick, irc->mynick, irc->myhost,
+ irc->channel, e?'+':'-', eflag, u->nick );
+ }
+
+ return 1;
}
void show_fingerprints(irc_t *irc, ConnContext *ctx)
@@ -965,9 +1147,13 @@ void no_keygen(gpointer w, void *data)
{
account_t *acc = (account_t *)data;
- /* TODO: remember that we didn't want a key? */
irc_usermsg(acc->irc, "proceeding without key, otr inoperable on %s/%s",
acc->user, acc->prpl->name);
+ /* TODO:
+ irc_usermsg(acc->irc, "setting otr policy for %s/%s to \"never\"",
+ acc->user, acc->prpl->name);
+ set_setstr(acc->set, "otr_policy", "never");
+ */
}
diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c
index 243ed7fd..dac18bae 100644
--- a/protocols/jabber/jabber.c
+++ b/protocols/jabber/jabber.c
@@ -510,6 +510,7 @@ void jabber_initmodule()
struct prpl *ret = g_new0( struct prpl, 1 );
ret->name = "jabber";
+ ret->mms = 0; /* no limit */
ret->login = jabber_login;
ret->init = jabber_init;
ret->logout = jabber_logout;
diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c
index a2e8519a..335ae894 100644
--- a/protocols/msn/msn.c
+++ b/protocols/msn/msn.c
@@ -371,6 +371,7 @@ void msn_initmodule()
struct prpl *ret = g_new0(struct prpl, 1);
ret->name = "msn";
+ ret->mms = 1409; /* this guess taken from libotr UPGRADING file */
ret->login = msn_login;
ret->init = msn_init;
ret->logout = msn_logout;
diff --git a/protocols/nogaim.c b/protocols/nogaim.c
index d8bfad14..138e2ce1 100644
--- a/protocols/nogaim.c
+++ b/protocols/nogaim.c
@@ -602,10 +602,9 @@ void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags,
/* else waste_any_state_information_for_now(); */
/* LISPy... */
- if( ( set_getbool( &ic->irc->set, "away_devoice" ) ) && /* Don't do a thing when user doesn't want it */
- ( u->online ) && /* Don't touch offline people */
- ( ( ( u->online != oo ) && !u->away ) || /* Voice joining people */
- ( ( u->online == oo ) && ( oa == !u->away ) ) ) ) /* (De)voice people changing state */
+ if( ( u->online ) && /* Don't touch offline people */
+ ( ( ( u->online != oo ) && !u->away ) || /* Do joining people */
+ ( ( u->online == oo ) && ( oa == !u->away ) ) ) ) /* Do people changing state */
{
char *from;
@@ -618,8 +617,14 @@ void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags,
from = g_strdup_printf( "%s!%s@%s", ic->irc->mynick, ic->irc->mynick,
ic->irc->myhost );
}
- irc_write( ic->irc, ":%s MODE %s %cv %s", from, ic->irc->channel,
- u->away?'-':'+', u->nick );
+ if(!strcmp(set_getstr(&ic->irc->set, "voice_buddies"), "notaway")) {
+ irc_write( ic->irc, ":%s MODE %s %cv %s", from, ic->irc->channel,
+ u->away?'-':'+', u->nick );
+ }
+ if(!strcmp(set_getstr(&ic->irc->set, "op_buddies"), "notaway")) {
+ irc_write( ic->irc, ":%s MODE %s %co %s", from, ic->irc->channel,
+ u->away?'-':'+', u->nick );
+ }
g_free( from );
}
}
diff --git a/protocols/nogaim.h b/protocols/nogaim.h
index 7d391edd..3eb640e2 100644
--- a/protocols/nogaim.h
+++ b/protocols/nogaim.h
@@ -135,6 +135,10 @@ struct prpl {
/* You should set this to the name of your protocol.
* - The user sees this name ie. when imcb_log() is used. */
const char *name;
+ /* Maximum Message Size of this protocol.
+ * - Introduced for OTR, in order to fragment large protocol messages.
+ * - 0 means "unlimited". */
+ unsigned int mms;
/* Added this one to be able to add per-account settings, don't think
* it should be used for anything else. You are supposed to use the
diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c
index 30ad4b68..9167f6a3 100644
--- a/protocols/oscar/oscar.c
+++ b/protocols/oscar/oscar.c
@@ -2602,6 +2602,7 @@ void oscar_initmodule()
{
struct prpl *ret = g_new0(struct prpl, 1);
ret->name = "oscar";
+ ret->mms = 2343; /* this guess taken from libotr UPGRADING file */
ret->away_states = oscar_away_states;
ret->init = oscar_init;
ret->login = oscar_login;
diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c
index 9f9ffcf7..52747bb4 100644
--- a/protocols/yahoo/yahoo.c
+++ b/protocols/yahoo/yahoo.c
@@ -353,6 +353,7 @@ void byahoo_initmodule( )
{
struct prpl *ret = g_new0(struct prpl, 1);
ret->name = "yahoo";
+ ret->mms = 832; /* this guess taken from libotr UPGRADING file */
ret->init = byahoo_init;
ret->login = byahoo_login;
diff --git a/set.c b/set.c
index 6f09843b..fa1933d5 100644
--- a/set.c
+++ b/set.c
@@ -208,28 +208,147 @@ char *set_eval_to_char( set_t *set, char *value )
return s;
}
-char *set_eval_ops( set_t *set, char *value )
+char *set_eval_op_root( set_t *set, char *value )
{
irc_t *irc = set->data;
+ char *ret = set_eval_bool(set, value);
+ int b = bool2int(ret);
- if( g_strcasecmp( value, "user" ) == 0 )
- irc_write( irc, ":%s!%s@%s MODE %s %s %s %s", irc->mynick, irc->mynick, irc->myhost,
- irc->channel, "+o-o", irc->nick, irc->mynick );
- else if( g_strcasecmp( value, "root" ) == 0 )
- irc_write( irc, ":%s!%s@%s MODE %s %s %s %s", irc->mynick, irc->mynick, irc->myhost,
- irc->channel, "-o+o", irc->nick, irc->mynick );
- else if( g_strcasecmp( value, "both" ) == 0 )
- irc_write( irc, ":%s!%s@%s MODE %s %s %s %s", irc->mynick, irc->mynick, irc->myhost,
- irc->channel, "+oo", irc->nick, irc->mynick );
- else if( g_strcasecmp( value, "none" ) == 0 )
- irc_write( irc, ":%s!%s@%s MODE %s %s %s %s", irc->mynick, irc->mynick, irc->myhost,
- irc->channel, "-oo", irc->nick, irc->mynick );
+ irc_write( irc, ":%s!%s@%s MODE %s %s %s", irc->mynick, irc->mynick, irc->myhost,
+ irc->channel, b?"+o":"-o", irc->mynick );
+ return ret;
+}
+
+char *set_eval_op_user( set_t *set, char *value )
+{
+ irc_t *irc = set->data;
+ char *ret = set_eval_bool(set, value);
+ int b = bool2int(ret);
+
+ irc_write( irc, ":%s!%s@%s MODE %s %s %s", irc->mynick, irc->mynick, irc->myhost,
+ irc->channel, b?"+o":"-o", irc->nick );
+ return ret;
+}
+
+/* generalized version of set_eval_op/voice_buddies */
+char *set_eval_mode_buddies( set_t *set, char *value, char modeflag )
+{
+ irc_t *irc = set->data;
+ char op[64], deop[64];
+ int nop=0, ndeop=0;
+ user_t *u;
+ int mode;
+
+ if(!strcmp(value, "false"))
+ mode=0;
+ else if(!strcmp(value, "encrypted"))
+ mode=1;
+ else if(!strcmp(value, "trusted"))
+ mode=2;
+ else if(!strcmp(value, "notaway"))
+ mode=3;
else
return NULL;
+ /* sorry for calling them op/deop - too lazy for search+replace :P */
+ op[0]='\0';
+ deop[0]='\0';
+ for(u=irc->users; u; u=u->next) {
+ /* we're only concerned with online buddies */
+ if(!u->ic || !u->online)
+ continue;
+
+ /* just in case... */
+ if(strlen(u->nick) >= 64)
+ continue;
+
+ /* dump out ops/deops when the corresponding name list fills up */
+ if(strlen(op)+strlen(u->nick)+2 > 64) {
+ char *flags = g_strnfill(nop, modeflag);
+ irc_write( irc, ":%s!%s@%s MODE %s +%s%s", irc->mynick, irc->mynick, irc->myhost,
+ irc->channel, flags, op );
+ op[0]='\0';
+ g_free(flags);
+ }
+ if(strlen(deop)+strlen(u->nick)+2 > 64) {
+ char *flags = g_strnfill(ndeop, modeflag);
+ irc_write( irc, ":%s!%s@%s MODE %s -%s%s", irc->mynick, irc->mynick, irc->myhost,
+ irc->channel, flags, deop );
+ deop[0]='\0';
+ g_free(flags);
+ }
+
+ switch(mode) {
+ /* "false" */
+ case 0:
+ g_strlcat(deop, " ", 64);
+ g_strlcat(deop, u->nick, 64);
+ ndeop++;
+ break;
+ /* "encrypted" */
+ case 1:
+ if(u->encrypted) {
+ g_strlcat(op, " ", 64);
+ g_strlcat(op, u->nick, 64);
+ nop++;
+ } else {
+ g_strlcat(deop, " ", 64);
+ g_strlcat(deop, u->nick, 64);
+ ndeop++;
+ }
+ break;
+ /* "trusted" */
+ case 2:
+ if(u->encrypted > 1) {
+ g_strlcat(op, " ", 64);
+ g_strlcat(op, u->nick, 64);
+ nop++;
+ } else {
+ g_strlcat(deop, " ", 64);
+ g_strlcat(deop, u->nick, 64);
+ ndeop++;
+ }
+ break;
+ /* "notaway" */
+ case 3:
+ if(u->away) {
+ g_strlcat(deop, " ", 64);
+ g_strlcat(deop, u->nick, 64);
+ ndeop++;
+ } else {
+ g_strlcat(op, " ", 64);
+ g_strlcat(op, u->nick, 64);
+ nop++;
+ }
+ }
+ }
+ /* dump anything left in op/deop lists */
+ if(*op) {
+ char *flags = g_strnfill(nop, modeflag);
+ irc_write( irc, ":%s!%s@%s MODE %s +%s%s", irc->mynick, irc->mynick, irc->myhost,
+ irc->channel, flags, op );
+ g_free(flags);
+ }
+ if(*deop) {
+ char *flags = g_strnfill(ndeop, modeflag);
+ irc_write( irc, ":%s!%s@%s MODE %s -%s%s", irc->mynick, irc->mynick, irc->myhost,
+ irc->channel, flags, deop );
+ g_free(flags);
+ }
+
return value;
}
+char *set_eval_op_buddies( set_t *set, char *value )
+{
+ return set_eval_mode_buddies(set, value, 'o');
+}
+
+char *set_eval_voice_buddies( set_t *set, char *value )
+{
+ return set_eval_mode_buddies(set, value, 'v');
+}
+
char *set_eval_charset( set_t *set, char *value )
{
GIConv cd;
diff --git a/set.h b/set.h
index 7dcbb869..b572cc2b 100644
--- a/set.h
+++ b/set.h
@@ -95,7 +95,10 @@ char *set_eval_bool( set_t *set, char *value );
/* Some not very generic evaluators that really shouldn't be here... */
char *set_eval_to_char( set_t *set, char *value );
-char *set_eval_ops( set_t *set, char *value );
+char *set_eval_op_root( set_t *set, char *value );
+char *set_eval_op_user( set_t *set, char *value );
+char *set_eval_op_buddies( set_t *set, char *value );
+char *set_eval_voice_buddies( set_t *set, char *value );
char *set_eval_charset( set_t *set, char *value );
#endif /* __SET_H__ */
diff --git a/user.h b/user.h
index 9d8a41a0..c2d6869d 100644
--- a/user.h
+++ b/user.h
@@ -36,6 +36,7 @@ typedef struct __USER
char is_private;
char online;
+ char encrypted;
char *handle;
char *group;