aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilmer van der Gaast <wilmer@gaast.net>2010-09-01 01:18:21 +0200
committerWilmer van der Gaast <wilmer@gaast.net>2010-09-01 01:18:21 +0200
commit0c85c08d210e16bb10dc283b4a1478ce53c0c1b1 (patch)
tree4d7fb00a0467ba51337fdc84cacade43b6baab97
parentf5c0d8e4dd3ce01945a6334a5d87c89a9f43b16b (diff)
Pluginify this thing a little bit. Not so much in the dynamically loadable
sense of the word, more in a way that core files don't have to include otr.h.
-rw-r--r--bitlbee.h2
-rw-r--r--irc.c23
-rw-r--r--irc.h27
-rw-r--r--otr.c88
-rw-r--r--otr.h6
-rw-r--r--storage.c19
6 files changed, 108 insertions, 57 deletions
diff --git a/bitlbee.h b/bitlbee.h
index e312dc4c..656e059a 100644
--- a/bitlbee.h
+++ b/bitlbee.h
@@ -141,7 +141,6 @@
#include "sock.h"
#include "misc.h"
#include "proxy.h"
-#include "otr.h"
typedef struct global {
/* In forked mode, child processes store the fd of the IPC socket here. */
@@ -153,7 +152,6 @@ typedef struct global {
GList *storage; /* The first backend in the list will be used for saving */
char *helpfile;
int restart;
- OtrlMessageAppOps otr_ops; /* collects interface functions required by OTR */
} global_t;
int bitlbee_daemon_init( void );
diff --git a/irc.c b/irc.c
index 836d5f81..ed705caa 100644
--- a/irc.c
+++ b/irc.c
@@ -28,6 +28,7 @@
#include "dcc.h"
GSList *irc_connection_list;
+GSList *irc_plugins;
static gboolean irc_userping( gpointer _irc, gint fd, b_input_condition cond );
static char *set_eval_charset( set_t *set, char *value );
@@ -41,6 +42,7 @@ irc_t *irc_new( int fd )
socklen_t socklen = sizeof( sock );
char *host = NULL, *myhost = NULL;
irc_user_t *iu;
+ GSList *l;
set_t *s;
bee_t *b;
@@ -163,6 +165,13 @@ irc_t *irc_new( int fd )
nogaim_init();
+ for( l = irc_plugins; l; l = l->next )
+ {
+ irc_plugin_t *p = l->data;
+ if( p->irc_new )
+ p->irc_new( irc );
+ }
+
return irc;
}
@@ -206,10 +215,19 @@ static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data );
void irc_free( irc_t * irc )
{
+ GSList *l;
+
irc->status |= USTATUS_SHUTDOWN;
log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd );
+ for( l = irc_plugins; l; l = l->next )
+ {
+ irc_plugin_t *p = l->data;
+ if( p->irc_free )
+ p->irc_free( irc );
+ }
+
if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->b->set, "save_on_quit" ) )
if( storage_save( irc, NULL, TRUE ) != STORAGE_OK )
log_message( LOGLVL_WARNING, "Error while saving settings for user %s", irc->user->nick );
@@ -931,3 +949,8 @@ static char *set_eval_bw_compat( set_t *set, char *value )
return SET_INVALID;
}
+
+void register_irc_plugin( const struct irc_plugin *p )
+{
+ irc_plugins = g_slist_prepend( irc_plugins, (gpointer) p );
+}
diff --git a/irc.h b/irc.h
index cd1f606e..516cc959 100644
--- a/irc.h
+++ b/irc.h
@@ -26,8 +26,6 @@
#ifndef _IRC_H
#define _IRC_H
-#include "otr.h"
-
#define IRC_MAX_LINE 512
#define IRC_MAX_ARGS 16
@@ -87,7 +85,8 @@ typedef struct irc
gint ping_source_id;
gint login_source_id; /* To slightly delay some events at login time. */
- otr_t *otr; /* OTR state and book keeping */
+ struct otr *otr; /* OTR state and book keeping, used by the OTR plugin.
+ TODO: Some mechanism for plugindata. */
struct bee *b;
} irc_t;
@@ -220,6 +219,26 @@ typedef enum
IRC_CDU_KICK,
} irc_channel_del_user_type_t;
+/* These are a glued a little bit to the core/bee layer and a little bit to
+ IRC. The first user is OTR, and I guess at some point we'll get to shape
+ this a little bit more as other uses come up. */
+typedef struct irc_plugin
+{
+ /* Called at the end of irc_new(). Can be used to add settings, etc. */
+ gboolean (*irc_new)( irc_t *irc );
+ /* At the end of irc_free(). */
+ void (*irc_free)( irc_t *irc );
+
+ /* Called by bee_irc_user_privmsg_cb(). Return NULL if you want to
+ abort sending the msg. */
+ char* (*filter_msg_out)( irc_user_t *iu, const char *msg, int flags );
+ /* Called by bee_irc_user_msg(). Return NULL if you swallowed the
+ message and don't want anything to go to the user. */
+ char* (*filter_msg_in)( irc_user_t *iu, const char *msg, int flags );
+} irc_plugin_t;
+
+extern GSList *irc_plugins; /* struct irc_plugin */
+
/* irc.c */
extern GSList *irc_connection_list;
@@ -245,6 +264,8 @@ int irc_check_login( irc_t *irc );
void irc_umode_set( irc_t *irc, const char *s, gboolean allow_priv );
+void register_irc_plugin( const struct irc_plugin *p );
+
/* irc_channel.c */
irc_channel_t *irc_channel_new( irc_t *irc, const char *name );
irc_channel_t *irc_channel_by_name( irc_t *irc, const char *name );
diff --git a/otr.c b/otr.c
index 9031d7de..1395f49a 100644
--- a/otr.c
+++ b/otr.c
@@ -108,6 +108,8 @@ typedef struct {
void *snd;
} pair_t;
+static OtrlMessageAppOps otr_ops; /* collects interface functions required by OTR */
+
/** misc. helpers/subroutines: **/
@@ -173,6 +175,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);
+/* functions to be called for certain events */
+static const struct irc_plugin otr_plugin;
+
/*** routines declared in otr.h: ***/
@@ -181,39 +186,52 @@ void otr_init(void)
OTRL_INIT;
/* fill global OtrlMessageAppOps */
- global.otr_ops.policy = &op_policy;
- global.otr_ops.create_privkey = &op_create_privkey;
- global.otr_ops.is_logged_in = &op_is_logged_in;
- global.otr_ops.inject_message = &op_inject_message;
- global.otr_ops.notify = NULL;
- global.otr_ops.display_otr_message = &op_display_otr_message;
- global.otr_ops.update_context_list = NULL;
- global.otr_ops.protocol_name = NULL;
- global.otr_ops.protocol_name_free = NULL;
- global.otr_ops.new_fingerprint = &op_new_fingerprint;
- global.otr_ops.write_fingerprints = &op_write_fingerprints;
- global.otr_ops.gone_secure = &op_gone_secure;
- global.otr_ops.gone_insecure = &op_gone_insecure;
- global.otr_ops.still_secure = &op_still_secure;
- global.otr_ops.log_message = &op_log_message;
- global.otr_ops.max_message_size = &op_max_message_size;
- global.otr_ops.account_name = &op_account_name;
- global.otr_ops.account_name_free = NULL;
+ otr_ops.policy = &op_policy;
+ otr_ops.create_privkey = &op_create_privkey;
+ otr_ops.is_logged_in = &op_is_logged_in;
+ otr_ops.inject_message = &op_inject_message;
+ otr_ops.notify = NULL;
+ otr_ops.display_otr_message = &op_display_otr_message;
+ otr_ops.update_context_list = NULL;
+ otr_ops.protocol_name = NULL;
+ otr_ops.protocol_name_free = NULL;
+ otr_ops.new_fingerprint = &op_new_fingerprint;
+ otr_ops.write_fingerprints = &op_write_fingerprints;
+ otr_ops.gone_secure = &op_gone_secure;
+ otr_ops.gone_insecure = &op_gone_insecure;
+ otr_ops.still_secure = &op_still_secure;
+ otr_ops.log_message = &op_log_message;
+ otr_ops.max_message_size = &op_max_message_size;
+ otr_ops.account_name = &op_account_name;
+ otr_ops.account_name_free = NULL;
root_command_add( "otr", 1, cmd_otr, 0 );
+ register_irc_plugin( &otr_plugin );
}
-otr_t *otr_new(void)
+gboolean otr_irc_new(irc_t *irc)
{
- otr_t *otr = g_new0(otr_t, 1);
-
- otr->us = otrl_userstate_create();
+ set_t *s;
+ GSList *l;
+
+ irc->otr = g_new0(otr_t, 1);
+ irc->otr->us = otrl_userstate_create();
- return otr;
+ s = set_add( &irc->b->set, "otr_color_encrypted", "true", set_eval_bool, irc );
+
+ s = set_add( &irc->b->set, "otr_policy", "oppurtunistic", set_eval_list, irc );
+ l = g_slist_prepend( NULL, "never" );
+ l = g_slist_prepend( l, "opportunistic" );
+ l = g_slist_prepend( l, "manual" );
+ l = g_slist_prepend( l, "always" );
+ s->eval_data = l;
+
+ return TRUE;
}
-void otr_free(otr_t *otr)
+void otr_irc_free(irc_t *irc)
{
+ otr_t *otr = irc->otr;
otrl_userstate_free(otr->us);
if(otr->keygen) {
kill(otr->keygen, SIGTERM);
@@ -338,7 +356,7 @@ char *otr_handle_message(struct im_connection *ic, const char *handle, const cha
return (g_strdup(msg));
}
- ignore_msg = otrl_message_receiving(irc->otr->us, &global.otr_ops, ic,
+ ignore_msg = otrl_message_receiving(irc->otr->us, &otr_ops, ic,
ic->acc->user, ic->acc->prpl->name, handle, msg, &newmsg,
&tlvs, NULL, NULL);
@@ -392,7 +410,7 @@ int otr_send_message(struct im_connection *ic, const char *handle, const char *m
return (ic->acc->prpl->buddy_msg(ic, (char*) handle, (char*) msg, flags));
}
- st = otrl_message_sending(irc->otr->us, &global.otr_ops, ic,
+ st = otrl_message_sending(irc->otr->us, &otr_ops, ic,
ic->acc->user, ic->acc->prpl->name, handle,
msg, NULL, &otrmsg, NULL, NULL);
if(st) {
@@ -408,7 +426,7 @@ int otr_send_message(struct im_connection *ic, const char *handle, const char *m
otrl_message_free(otrmsg);
return 1;
}
- st = otrl_message_fragment_and_send(&global.otr_ops, ic, ctx,
+ st = otrl_message_fragment_and_send(&otr_ops, ic, ctx,
otrmsg, OTRL_FRAGMENT_SEND_ALL, NULL);
otrl_message_free(otrmsg);
} else {
@@ -420,6 +438,12 @@ int otr_send_message(struct im_connection *ic, const char *handle, const char *m
return st;
}
+static const struct irc_plugin otr_plugin =
+{
+ otr_irc_new,
+ otr_irc_free,
+};
+
static void cmd_otr(irc_t *irc, char **args)
{
const command_t *cmd;
@@ -662,7 +686,7 @@ void cmd_otr_disconnect(irc_t *irc, char **args)
return;
}
- otrl_message_disconnect(irc->otr->us, &global.otr_ops,
+ otrl_message_disconnect(irc->otr->us, &otr_ops,
u->bu->ic, u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, u->bu->handle);
/* for some reason, libotr (3.1.0) doesn't do this itself: */
@@ -720,7 +744,7 @@ void cmd_otr_smp(irc_t *irc, char **args)
log_message(LOGLVL_INFO,
"SMP already in phase %d, sending abort before reinitiating",
ctx->smstate->nextExpected+1);
- otrl_message_abort_smp(irc->otr->us, &global.otr_ops, u->bu->ic, ctx);
+ otrl_message_abort_smp(irc->otr->us, &otr_ops, u->bu->ic, ctx);
otrl_sm_state_free(ctx->smstate);
}
@@ -728,14 +752,14 @@ void cmd_otr_smp(irc_t *irc, char **args)
is completed or aborted! */
if(ctx->smstate->secret == NULL) {
irc_usermsg(irc, "smp: initiating with %s...", u->nick);
- otrl_message_initiate_smp(irc->otr->us, &global.otr_ops,
+ otrl_message_initiate_smp(irc->otr->us, &otr_ops,
u->bu->ic, ctx, (unsigned char *)args[2], strlen(args[2]));
/* 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);
- otrl_message_respond_smp(irc->otr->us, &global.otr_ops,
+ otrl_message_respond_smp(irc->otr->us, &otr_ops,
u->bu->ic, ctx, (unsigned char *)args[2], strlen(args[2]));
/* smp is now in EXPECT3 */
}
@@ -1049,7 +1073,7 @@ void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs)
{
irc_t *irc = ic->bee->ui_data;
OtrlUserState us = irc->otr->us;
- OtrlMessageAppOps *ops = &global.otr_ops;
+ OtrlMessageAppOps *ops = &otr_ops;
OtrlTLV *tlv = NULL;
ConnContext *context;
NextExpectedSMP nextMsg;
diff --git a/otr.h b/otr.h
index c0c06e76..c18d12af 100644
--- a/otr.h
+++ b/otr.h
@@ -71,10 +71,6 @@ typedef struct otr {
/* called from main() */
void otr_init(void);
-/* called from irc_new()/irc_free() */
-otr_t *otr_new();
-void otr_free(otr_t *otr);
-
/* called by storage_* functions */
void otr_load(struct irc *irc);
void otr_save(struct irc *irc);
@@ -97,8 +93,6 @@ int otr_send_message(struct im_connection *ic, const char *handle, const char *m
typedef void otr_t;
typedef void *OtrlMessageAppOps;
-#define otr_init() {}
-#define otr_new() (NULL)
#define otr_free(otr) {}
#define otr_load(irc) {}
#define otr_save(irc) {}
diff --git a/storage.c b/storage.c
index 0c534858..ad1833fc 100644
--- a/storage.c
+++ b/storage.c
@@ -27,7 +27,6 @@
#define BITLBEE_CORE
#include "bitlbee.h"
-#include "otr.h"
extern storage_t storage_text;
extern storage_t storage_xml;
@@ -114,10 +113,9 @@ storage_status_t storage_load (irc_t * irc, const char *password)
storage_status_t status;
status = st->load(irc, password);
- if (status == STORAGE_OK) {
- otr_load(irc);
+ if (status == STORAGE_OK)
return status;
- }
+
if (status != STORAGE_NO_SUCH_USER)
return status;
}
@@ -138,8 +136,7 @@ storage_status_t storage_save (irc_t *irc, char *password, int overwrite)
} else if ((irc->status & USTATUS_IDENTIFIED) == 0) {
return STORAGE_NO_SUCH_USER;
}
-
- otr_save(irc);
+
st = ((storage_t *)global.storage->data)->save(irc, overwrite);
if (password != NULL) {
@@ -165,9 +162,6 @@ storage_status_t storage_remove (const char *nick, const char *password)
if (status != STORAGE_NO_SUCH_USER && status != STORAGE_OK)
ret = status;
}
- if (ret == STORAGE_OK) {
- otr_remove(nick);
- }
return ret;
}
@@ -181,14 +175,12 @@ storage_status_t storage_rename (const char *onick, const char *nnick, const cha
GList *gl = global.storage;
storage_t *primary_storage = gl->data;
irc_t *irc;
-
+
/* First, try to rename in the current write backend, assuming onick
* is stored there */
status = primary_storage->rename(onick, nnick, password);
- if (status != STORAGE_NO_SUCH_USER) {
- otr_rename(onick, nnick);
+ if (status != STORAGE_NO_SUCH_USER)
return status;
- }
/* Try to load from a migration backend and save to the current backend.
* Explicitly remove the account from the migration backend as otherwise
@@ -212,7 +204,6 @@ storage_status_t storage_rename (const char *onick, const char *nnick, const cha
irc_free(irc);
storage_remove(onick, password);
- otr_rename(onick, nnick);
return STORAGE_OK;
}