aboutsummaryrefslogtreecommitdiffstats
path: root/protocols
diff options
context:
space:
mode:
Diffstat (limited to 'protocols')
-rw-r--r--protocols/Makefile3
-rw-r--r--protocols/account.c360
-rw-r--r--protocols/account.h72
-rw-r--r--protocols/bee.c95
-rw-r--r--protocols/bee.h147
-rw-r--r--protocols/bee_chat.c234
-rw-r--r--protocols/bee_ft.c66
-rw-r--r--protocols/bee_user.c246
-rw-r--r--protocols/chat.c192
-rw-r--r--protocols/chat.h51
-rw-r--r--protocols/ft.h7
-rw-r--r--protocols/jabber/conference.c6
-rw-r--r--protocols/jabber/iq.c9
-rw-r--r--protocols/jabber/jabber.c4
-rw-r--r--protocols/jabber/jabber_util.c8
-rw-r--r--protocols/jabber/presence.c5
-rw-r--r--protocols/jabber/s5bytestream.c14
-rw-r--r--protocols/jabber/si.c10
-rw-r--r--protocols/msn/Makefile2
-rw-r--r--protocols/msn/msn.c9
-rw-r--r--protocols/msn/msn_util.c3
-rw-r--r--protocols/msn/sb.c24
-rw-r--r--protocols/nogaim.c886
-rw-r--r--protocols/nogaim.h23
-rw-r--r--protocols/oscar/oscar.c34
-rw-r--r--protocols/purple/ft.c14
-rw-r--r--protocols/purple/purple.c21
-rw-r--r--protocols/twitter/twitter_lib.c2
-rw-r--r--protocols/yahoo/yahoo.c24
29 files changed, 1643 insertions, 928 deletions
diff --git a/protocols/Makefile b/protocols/Makefile
index 57fcd7eb..d4aa6e14 100644
--- a/protocols/Makefile
+++ b/protocols/Makefile
@@ -12,7 +12,8 @@ SRCDIR := $(SRCDIR)protocols/
endif
# [SH] Program variables
-objects = nogaim.o
+objects = account.o bee.o bee_chat.o bee_ft.o bee_user.o nogaim.o
+
# [SH] The next two lines should contain the directory name (in $(subdirs))
# and the name of the object file, which should be linked into
diff --git a/protocols/account.c b/protocols/account.c
new file mode 100644
index 00000000..0bacea74
--- /dev/null
+++ b/protocols/account.c
@@ -0,0 +1,360 @@
+ /********************************************************************\
+ * BitlBee -- An IRC to other IM-networks gateway *
+ * *
+ * Copyright 2002-2010 Wilmer van der Gaast and others *
+ \********************************************************************/
+
+/* Account management functions */
+
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License with
+ the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+ Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#define BITLBEE_CORE
+#include "bitlbee.h"
+#include "account.h"
+#include "chat.h"
+
+account_t *account_add( bee_t *bee, struct prpl *prpl, char *user, char *pass )
+{
+ account_t *a;
+ set_t *s;
+
+ if( bee->accounts )
+ {
+ for( a = bee->accounts; a->next; a = a->next );
+ a = a->next = g_new0( account_t, 1 );
+ }
+ else
+ {
+ bee->accounts = a = g_new0 ( account_t, 1 );
+ }
+
+ a->prpl = prpl;
+ a->user = g_strdup( user );
+ a->pass = g_strdup( pass );
+ a->auto_connect = 1;
+ a->bee = bee;
+
+ s = set_add( &a->set, "auto_connect", "true", set_eval_account, a );
+ s->flags |= ACC_SET_NOSAVE;
+
+ s = set_add( &a->set, "auto_reconnect", "true", set_eval_bool, a );
+
+ s = set_add( &a->set, "nick_source", "handle", NULL, a );
+
+ s = set_add( &a->set, "password", NULL, set_eval_account, a );
+ s->flags |= ACC_SET_NOSAVE | SET_NULL_OK;
+
+ s = set_add( &a->set, "username", NULL, set_eval_account, a );
+ s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
+ set_setstr( &a->set, "username", user );
+
+ a->nicks = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free );
+
+ /* This function adds some more settings (and might want to do more
+ things that have to be done now, although I can't think of anything. */
+ if( prpl->init )
+ prpl->init( a );
+
+ s = set_add( &a->set, "away", NULL, set_eval_account, a );
+ s->flags |= SET_NULL_OK;
+
+ if( a->flags & ACC_FLAG_STATUS_MESSAGE )
+ {
+ s = set_add( &a->set, "status", NULL, set_eval_account, a );
+ s->flags |= SET_NULL_OK;
+ }
+
+ return a;
+}
+
+char *set_eval_account( set_t *set, char *value )
+{
+ account_t *acc = set->data;
+
+ /* Double-check: We refuse to edit on-line accounts. */
+ if( set->flags & ACC_SET_OFFLINE_ONLY && acc->ic )
+ return SET_INVALID;
+
+ if( strcmp( set->key, "server" ) == 0 )
+ {
+ g_free( acc->server );
+ if( value && *value )
+ {
+ acc->server = g_strdup( value );
+ return value;
+ }
+ else
+ {
+ acc->server = g_strdup( set->def );
+ return g_strdup( set->def );
+ }
+ }
+ else if( strcmp( set->key, "username" ) == 0 )
+ {
+ g_free( acc->user );
+ acc->user = g_strdup( value );
+ return value;
+ }
+ else if( strcmp( set->key, "password" ) == 0 )
+ {
+ if( value )
+ {
+ g_free( acc->pass );
+ acc->pass = g_strdup( value );
+ return NULL; /* password shouldn't be visible in plaintext! */
+ }
+ else
+ {
+ /* NULL can (should) be stored in the set_t
+ variable, but is otherwise not correct. */
+ return SET_INVALID;
+ }
+ }
+ else if( strcmp( set->key, "auto_connect" ) == 0 )
+ {
+ if( !is_bool( value ) )
+ return SET_INVALID;
+
+ acc->auto_connect = bool2int( value );
+ return value;
+ }
+ else if( strcmp( set->key, "away" ) == 0 ||
+ strcmp( set->key, "status" ) == 0 )
+ {
+ if( acc->ic && acc->ic->flags & OPT_LOGGED_IN )
+ {
+ /* If we're currently on-line, set the var now already
+ (bit of a hack) and send an update. */
+ g_free( set->value );
+ set->value = g_strdup( value );
+
+ imc_away_send_update( acc->ic );
+ }
+
+ return value;
+ }
+
+ return SET_INVALID;
+}
+
+account_t *account_get( bee_t *bee, char *id )
+{
+ account_t *a, *ret = NULL;
+ char *handle, *s;
+ int nr;
+
+ /* This checks if the id string ends with (...) */
+ if( ( handle = strchr( id, '(' ) ) && ( s = strchr( handle, ')' ) ) && s[1] == 0 )
+ {
+ struct prpl *proto;
+
+ *s = *handle = 0;
+ handle ++;
+
+ if( ( proto = find_protocol( id ) ) )
+ {
+ for( a = bee->accounts; a; a = a->next )
+ if( a->prpl == proto &&
+ a->prpl->handle_cmp( handle, a->user ) == 0 )
+ ret = a;
+ }
+
+ /* Restore the string. */
+ handle --;
+ *handle = '(';
+ *s = ')';
+
+ if( ret )
+ return ret;
+ }
+
+ if( sscanf( id, "%d", &nr ) == 1 && nr < 1000 )
+ {
+ for( a = bee->accounts; a; a = a->next )
+ if( ( nr-- ) == 0 )
+ return( a );
+
+ return( NULL );
+ }
+
+ for( a = bee->accounts; a; a = a->next )
+ {
+ if( g_strcasecmp( id, a->prpl->name ) == 0 )
+ {
+ if( !ret )
+ ret = a;
+ else
+ return( NULL ); /* We don't want to match more than one... */
+ }
+ else if( strstr( a->user, id ) )
+ {
+ if( !ret )
+ ret = a;
+ else
+ return( NULL );
+ }
+ }
+
+ return( ret );
+}
+
+void account_del( bee_t *bee, account_t *acc )
+{
+ account_t *a, *l = NULL;
+
+ if( acc->ic )
+ /* Caller should have checked, accounts still in use can't be deleted. */
+ return;
+
+ for( a = bee->accounts; a; a = (l=a)->next )
+ if( a == acc )
+ {
+ if( l )
+ l->next = a->next;
+ else
+ bee->accounts = a->next;
+
+ /** FIXME
+ for( c = bee->chatrooms; c; c = nc )
+ {
+ nc = c->next;
+ if( acc == c->acc )
+ chat_del( bee, c );
+ }
+ */
+
+ while( a->set )
+ set_del( &a->set, a->set->key );
+
+ g_hash_table_destroy( a->nicks );
+
+ g_free( a->user );
+ g_free( a->pass );
+ g_free( a->server );
+ if( a->reconnect ) /* This prevents any reconnect still queued to happen */
+ cancel_auto_reconnect( a );
+ g_free( a );
+
+ break;
+ }
+}
+
+void account_on( bee_t *bee, account_t *a )
+{
+ if( a->ic )
+ {
+ /* Trying to enable an already-enabled account */
+ return;
+ }
+
+ cancel_auto_reconnect( a );
+
+ a->reconnect = 0;
+ a->prpl->login( a );
+}
+
+void account_off( bee_t *bee, account_t *a )
+{
+ imc_logout( a->ic, FALSE );
+ a->ic = NULL;
+ if( a->reconnect )
+ {
+ /* Shouldn't happen */
+ cancel_auto_reconnect( a );
+ }
+}
+
+struct account_reconnect_delay
+{
+ int start;
+ char op;
+ int step;
+ int max;
+};
+
+int account_reconnect_delay_parse( char *value, struct account_reconnect_delay *p )
+{
+ memset( p, 0, sizeof( *p ) );
+ /* A whole day seems like a sane "maximum maximum". */
+ p->max = 86400;
+
+ /* Format: /[0-9]+([*+][0-9]+(<[0-9+])?)?/ */
+ while( *value && isdigit( *value ) )
+ p->start = p->start * 10 + *value++ - '0';
+
+ /* Sure, call me evil for implementing my own fscanf here, but it's
+ dead simple and I immediately know where to continue parsing. */
+
+ if( *value == 0 )
+ /* If the string ends now, the delay is constant. */
+ return 1;
+ else if( *value != '+' && *value != '*' )
+ /* Otherwise allow either a + or a * */
+ return 0;
+
+ p->op = *value++;
+
+ /* + or * the delay by this number every time. */
+ while( *value && isdigit( *value ) )
+ p->step = p->step * 10 + *value++ - '0';
+
+ if( *value == 0 )
+ /* Use the default maximum (one day). */
+ return 1;
+ else if( *value != '<' )
+ return 0;
+
+ p->max = 0;
+ value ++;
+ while( *value && isdigit( *value ) )
+ p->max = p->max * 10 + *value++ - '0';
+
+ return p->max > 0;
+}
+
+char *set_eval_account_reconnect_delay( set_t *set, char *value )
+{
+ struct account_reconnect_delay p;
+
+ return account_reconnect_delay_parse( value, &p ) ? value : SET_INVALID;
+}
+
+int account_reconnect_delay( account_t *a )
+{
+ char *setting = set_getstr( &a->bee->set, "auto_reconnect_delay" );
+ struct account_reconnect_delay p;
+
+ if( account_reconnect_delay_parse( setting, &p ) )
+ {
+ if( a->auto_reconnect_delay == 0 )
+ a->auto_reconnect_delay = p.start;
+ else if( p.op == '+' )
+ a->auto_reconnect_delay += p.step;
+ else if( p.op == '*' )
+ a->auto_reconnect_delay *= p.step;
+
+ if( a->auto_reconnect_delay > p.max )
+ a->auto_reconnect_delay = p.max;
+ }
+ else
+ {
+ a->auto_reconnect_delay = 0;
+ }
+
+ return a->auto_reconnect_delay;
+}
diff --git a/protocols/account.h b/protocols/account.h
new file mode 100644
index 00000000..be27542e
--- /dev/null
+++ b/protocols/account.h
@@ -0,0 +1,72 @@
+ /********************************************************************\
+ * BitlBee -- An IRC to other IM-networks gateway *
+ * *
+ * Copyright 2002-2004 Wilmer van der Gaast and others *
+ \********************************************************************/
+
+/* Account management functions */
+
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License with
+ the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+ Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _ACCOUNT_H
+#define _ACCOUNT_H
+
+typedef struct account
+{
+ struct prpl *prpl;
+ char *user;
+ char *pass;
+ char *server;
+
+ int auto_connect;
+ int auto_reconnect_delay;
+ int reconnect;
+ int flags;
+
+ set_t *set;
+ GHashTable *nicks;
+
+ struct bee *bee;
+ struct im_connection *ic;
+ struct account *next;
+} account_t;
+
+account_t *account_add( bee_t *bee, struct prpl *prpl, char *user, char *pass );
+account_t *account_get( bee_t *bee, char *id );
+void account_del( bee_t *bee, account_t *acc );
+void account_on( bee_t *bee, account_t *a );
+void account_off( bee_t *bee, account_t *a );
+
+char *set_eval_account( set_t *set, char *value );
+char *set_eval_account_reconnect_delay( set_t *set, char *value );
+int account_reconnect_delay( account_t *a );
+
+typedef enum
+{
+ ACC_SET_NOSAVE = 0x01, /* Don't save this setting (i.e. stored elsewhere). */
+ ACC_SET_OFFLINE_ONLY = 0x02, /* Allow changes only if the acct is offline. */
+ ACC_SET_ONLINE_ONLY = 0x04, /* Allow changes only if the acct is online. */
+} account_set_flag_t;
+
+typedef enum
+{
+ ACC_FLAG_AWAY_MESSAGE = 0x01, /* Supports away messages instead of just states. */
+ ACC_FLAG_STATUS_MESSAGE = 0x02, /* Supports status messages (without being away). */
+} account_flag_t;
+
+#endif
diff --git a/protocols/bee.c b/protocols/bee.c
new file mode 100644
index 00000000..c5eeee17
--- /dev/null
+++ b/protocols/bee.c
@@ -0,0 +1,95 @@
+ /********************************************************************\
+ * BitlBee -- An IRC to other IM-networks gateway *
+ * *
+ * Copyright 2002-2010 Wilmer van der Gaast and others *
+ \********************************************************************/
+
+/* Some IM-core stuff */
+
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License with
+ the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+ Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#define BITLBEE_CORE
+#include "bitlbee.h"
+
+static char *set_eval_away_status( set_t *set, char *value );
+
+bee_t *bee_new()
+{
+ bee_t *b = g_new0( bee_t, 1 );
+ set_t *s;
+
+ s = set_add( &b->set, "away", NULL, set_eval_away_status, b );
+ s->flags |= SET_NULL_OK;
+ s = set_add( &b->set, "auto_connect", "true", set_eval_bool, b );
+ s = set_add( &b->set, "auto_reconnect", "true", set_eval_bool, b );
+ s = set_add( &b->set, "auto_reconnect_delay", "5*3<900", set_eval_account_reconnect_delay, b );
+ s = set_add( &b->set, "debug", "false", set_eval_bool, b );
+ s = set_add( &b->set, "save_on_quit", "true", set_eval_bool, b );
+ s = set_add( &b->set, "status", NULL, set_eval_away_status, b );
+ s->flags |= SET_NULL_OK;
+ s = set_add( &b->set, "strip_html", "true", NULL, b );
+
+ b->user = g_malloc( 1 );
+
+ return b;
+}
+
+void bee_free( bee_t *b )
+{
+ while( b->accounts )
+ {
+ if( b->accounts->ic )
+ imc_logout( b->accounts->ic, FALSE );
+ else if( b->accounts->reconnect )
+ cancel_auto_reconnect( b->accounts );
+
+ if( b->accounts->ic == NULL )
+ account_del( b, b->accounts );
+ else
+ /* Nasty hack, but account_del() doesn't work in this
+ case and we don't want infinite loops, do we? ;-) */
+ b->accounts = b->accounts->next;
+ }
+
+ while( b->set )
+ set_del( &b->set, b->set->key );
+
+ bee_group_free( b );
+
+ g_free( b->user );
+ g_free( b );
+}
+
+static char *set_eval_away_status( set_t *set, char *value )
+{
+ bee_t *bee = set->data;
+ account_t *a;
+
+ g_free( set->value );
+ set->value = g_strdup( value );
+
+ for( a = bee->accounts; a; a = a->next )
+ {
+ struct im_connection *ic = a->ic;
+
+ if( ic && ic->flags & OPT_LOGGED_IN )
+ imc_away_send_update( ic );
+ }
+
+ return value;
+}
diff --git a/protocols/bee.h b/protocols/bee.h
new file mode 100644
index 00000000..c3230f47
--- /dev/null
+++ b/protocols/bee.h
@@ -0,0 +1,147 @@
+ /********************************************************************\
+ * BitlBee -- An IRC to other IM-networks gateway *
+ * *
+ * Copyright 2002-2010 Wilmer van der Gaast and others *
+ \********************************************************************/
+
+/* Stuff to handle, save and search buddies */
+
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License with
+ the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+ Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __BEE_H__
+#define __BEE_H__
+
+struct bee_ui_funcs;
+struct groupchat;
+
+typedef struct bee
+{
+ struct set *set;
+
+ GSList *users;
+ GSList *groups;
+ struct account *accounts; /* TODO(wilmer): Use GSList here too? */
+
+ /* Symbolic, to refer to the local user (who has no real bee_user
+ object). Not to be used by anything except so far imcb_chat_add/
+ remove_buddy(). This seems slightly cleaner than abusing NULL. */
+ struct bee_user *user;
+
+ const struct bee_ui_funcs *ui;
+ void *ui_data;
+} bee_t;
+
+bee_t *bee_new();
+void bee_free( bee_t *b );
+
+typedef enum
+{
+ BEE_USER_ONLINE = 1, /* Compatibility with old OPT_LOGGED_IN flag */
+ BEE_USER_AWAY = 4, /* Compatibility with old OPT_AWAY flag */
+ BEE_USER_LOCAL = 256, /* Locally-added contacts (not in real contact list) */
+} bee_user_flags_t;
+
+typedef struct bee_user
+{
+ struct im_connection *ic;
+ char *handle;
+ char *fullname;
+ struct bee_group *group;
+
+ bee_user_flags_t flags;
+ char *status;
+ char *status_msg;
+
+ time_t login_time, idle_time;
+
+ bee_t *bee;
+ void *ui_data;
+} bee_user_t;
+
+typedef struct bee_group
+{
+ char *key;
+ char *name;
+} bee_group_t;
+
+typedef struct bee_ui_funcs
+{
+ gboolean (*user_new)( bee_t *bee, struct bee_user *bu );
+ gboolean (*user_free)( bee_t *bee, struct bee_user *bu );
+ gboolean (*user_fullname)( bee_t *bee, bee_user_t *bu );
+ gboolean (*user_nick_hint)( bee_t *bee, bee_user_t *bu, const char *hint );
+ gboolean (*user_group)( bee_t *bee, bee_user_t *bu );
+ gboolean (*user_status)( bee_t *bee, struct bee_user *bu, struct bee_user *old );
+ gboolean (*user_msg)( bee_t *bee, bee_user_t *bu, const char *msg, time_t sent_at );
+ gboolean (*user_typing)( bee_t *bee, bee_user_t *bu, guint32 flags );
+
+ gboolean (*chat_new)( bee_t *bee, struct groupchat *c );
+ gboolean (*chat_free)( bee_t *bee, struct groupchat *c );
+ gboolean (*chat_log)( bee_t *bee, struct groupchat *c, const char *text );
+ gboolean (*chat_msg)( bee_t *bee, struct groupchat *c, bee_user_t *bu, const char *msg, time_t sent_at );
+ gboolean (*chat_add_user)( bee_t *bee, struct groupchat *c, bee_user_t *bu );
+ gboolean (*chat_remove_user)( bee_t *bee, struct groupchat *c, bee_user_t *bu );
+ gboolean (*chat_topic)( bee_t *bee, struct groupchat *c, const char *new, bee_user_t *bu );
+ gboolean (*chat_name_hint)( bee_t *bee, struct groupchat *c, const char *name );
+
+ struct file_transfer* (*ft_in_start)( bee_t *bee, bee_user_t *bu, const char *file_name, size_t file_size );
+ gboolean (*ft_out_start)( struct im_connection *ic, struct file_transfer *ft );
+ void (*ft_close)( struct im_connection *ic, struct file_transfer *ft );
+ void (*ft_finished)( struct im_connection *ic, struct file_transfer *ft );
+} bee_ui_funcs_t;
+
+
+/* bee.c */
+bee_t *bee_new();
+void bee_free( bee_t *b );
+
+/* bee_user.c */
+bee_user_t *bee_user_new( bee_t *bee, struct im_connection *ic, const char *handle, bee_user_flags_t flags );
+int bee_user_free( bee_t *bee, bee_user_t *bu );
+bee_user_t *bee_user_by_handle( bee_t *bee, struct im_connection *ic, const char *handle );
+int bee_user_msg( bee_t *bee, bee_user_t *bu, const char *msg, int flags );
+bee_group_t *bee_group_by_name( bee_t *bee, const char *name, gboolean creat );
+void bee_group_free( bee_t *bee );
+
+/* Callbacks from IM modules to core: */
+/* Buddy activity */
+/* To manipulate the status of a handle.
+ * - flags can be |='d with OPT_* constants. You will need at least:
+ * OPT_LOGGED_IN and OPT_AWAY.
+ * - 'state' and 'message' can be NULL */
+G_MODULE_EXPORT void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message );
+G_MODULE_EXPORT void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle );
+/* Call when a handle says something. 'flags' and 'sent_at may be just 0. */
+G_MODULE_EXPORT void imcb_buddy_msg( struct im_connection *ic, const char *handle, char *msg, guint32 flags, time_t sent_at );
+
+/* bee_chat.c */
+#if 0
+struct groupchat *imcb_chat_new( struct im_connection *ic, const char *handle );
+void imcb_chat_name_hint( struct groupchat *c, const char *name );
+void imcb_chat_free( struct groupchat *c );
+void imcb_chat_msg( struct groupchat *c, const char *who, char *msg, uint32_t flags, time_t sent_at );
+void imcb_chat_log( struct groupchat *c, char *format, ... );
+void imcb_chat_topic( struct groupchat *c, char *who, char *topic, time_t set_at );
+void imcb_chat_add_buddy( struct groupchat *b, const char *handle );
+void imcb_chat_remove_buddy( struct groupchat *b, const char *handle, const char *reason );
+static int remove_chat_buddy_silent( struct groupchat *b, const char *handle );
+#endif
+int bee_chat_msg( bee_t *bee, struct groupchat *c, const char *msg, int flags );
+struct groupchat *bee_chat_by_title( bee_t *bee, struct im_connection *ic, const char *title );
+
+#endif /* __BEE_H__ */
diff --git a/protocols/bee_chat.c b/protocols/bee_chat.c
new file mode 100644
index 00000000..3be6f189
--- /dev/null
+++ b/protocols/bee_chat.c
@@ -0,0 +1,234 @@
+ /********************************************************************\
+ * BitlBee -- An IRC to other IM-networks gateway *
+ * *
+ * Copyright 2002-2010 Wilmer van der Gaast and others *
+ \********************************************************************/
+
+/* Stuff to handle rooms */
+
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License with
+ the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+ Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#define BITLBEE_CORE
+#include "bitlbee.h"
+
+struct groupchat *imcb_chat_new( struct im_connection *ic, const char *handle )
+{
+ struct groupchat *c = g_new0( struct groupchat, 1 );
+ bee_t *bee = ic->bee;
+
+ /* This one just creates the conversation structure, user won't see
+ anything yet until s/he is joined to the conversation. (This
+ allows you to add other already present participants first.) */
+
+ ic->groupchats = g_slist_prepend( ic->groupchats, c );
+ c->ic = ic;
+ c->title = g_strdup( handle );
+ c->topic = g_strdup_printf( "BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!", c->title );
+
+ if( set_getbool( &ic->bee->set, "debug" ) )
+ imcb_log( ic, "Creating new conversation: (id=%p,handle=%s)", c, handle );
+
+ if( bee->ui->chat_new )
+ bee->ui->chat_new( bee, c );
+
+ return c;
+}
+
+void imcb_chat_name_hint( struct groupchat *c, const char *name )
+{
+ bee_t *bee = c->ic->bee;
+
+ if( bee->ui->chat_name_hint )
+ bee->ui->chat_name_hint( bee, c, name );
+}
+
+void imcb_chat_free( struct groupchat *c )
+{
+ struct im_connection *ic = c->ic;
+ bee_t *bee = ic->bee;
+ GList *ir;
+
+ if( bee->ui->chat_free )
+ bee->ui->chat_free( bee, c );
+
+ if( set_getbool( &ic->bee->set, "debug" ) )
+ imcb_log( ic, "You were removed from conversation %p", c );
+
+ ic->groupchats = g_slist_remove( ic->groupchats, c );
+
+ for( ir = c->in_room; ir; ir = ir->next )
+ g_free( ir->data );
+ g_list_free( c->in_room );
+ g_free( c->title );
+ g_free( c->topic );
+ g_free( c );
+}
+
+void imcb_chat_msg( struct groupchat *c, const char *who, char *msg, uint32_t flags, time_t sent_at )
+{
+ struct im_connection *ic = c->ic;
+ bee_t *bee = ic->bee;
+ bee_user_t *bu;
+ char *s;
+
+ /* Gaim sends own messages through this too. IRC doesn't want this, so kill them */
+ if( g_strcasecmp( who, ic->acc->user ) == 0 )
+ return;
+
+ bu = bee_user_by_handle( bee, ic, who );
+
+ s = set_getstr( &ic->bee->set, "strip_html" );
+ if( ( g_strcasecmp( s, "always" ) == 0 ) ||
+ ( ( ic->flags & OPT_DOES_HTML ) && s ) )
+ strip_html( msg );
+
+ if( bu && bee->ui->chat_msg )
+ bee->ui->chat_msg( bee, c, bu, msg, sent_at );
+ else
+ imcb_chat_log( c, "Message from unknown participant %s: %s", who, msg );
+}
+
+void imcb_chat_log( struct groupchat *c, char *format, ... )
+{
+ struct im_connection *ic = c->ic;
+ bee_t *bee = ic->bee;
+ va_list params;
+ char *text;
+
+ if( !bee->ui->chat_log )
+ return;
+
+ va_start( params, format );
+ text = g_strdup_vprintf( format, params );
+ va_end( params );
+
+ bee->ui->chat_log( bee, c, text );
+ g_free( text );
+}
+
+void imcb_chat_topic( struct groupchat *c, char *who, char *topic, time_t set_at )
+{
+ struct im_connection *ic = c->ic;
+ bee_t *bee = ic->bee;
+ bee_user_t *bu;
+
+ if( !bee->ui->chat_topic )
+ return;
+
+ if( who == NULL)
+ bu = NULL;
+ else if( g_strcasecmp( who, ic->acc->user ) == 0 )
+ bu = bee->user;
+ else
+ bu = bee_user_by_handle( bee, ic, who );
+
+ if( ( g_strcasecmp( set_getstr( &ic->bee->set, "strip_html" ), "always" ) == 0 ) ||
+ ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->bee->set, "strip_html" ) ) )
+ strip_html( topic );
+
+ bee->ui->chat_topic( bee, c, topic, bu );
+}
+
+void imcb_chat_add_buddy( struct groupchat *c, const char *handle )
+{
+ struct im_connection *ic = c->ic;
+ bee_t *bee = ic->bee;
+ bee_user_t *bu = bee_user_by_handle( bee, ic, handle );
+ gboolean me;
+
+ if( set_getbool( &c->ic->bee->set, "debug" ) )
+ imcb_log( c->ic, "User %s added to conversation %p", handle, c );
+
+ me = ic->acc->prpl->handle_cmp( handle, ic->acc->user ) == 0;
+
+ /* Most protocols allow people to join, even when they're not in
+ your contact list. Try to handle that here */
+ if( !me && !bu )
+ bu = bee_user_new( bee, ic, handle, BEE_USER_LOCAL );
+
+ /* Add the handle to the room userlist */
+ /* TODO: Use bu instead of a string */
+ c->in_room = g_list_append( c->in_room, g_strdup( handle ) );
+
+ if( bee->ui->chat_add_user )
+ bee->ui->chat_add_user( bee, c, me ? bee->user : bu );
+
+ if( me )
+ c->joined = 1;
+}
+
+void imcb_chat_remove_buddy( struct groupchat *c, const char *handle, const char *reason )
+{
+ struct im_connection *ic = c->ic;
+ bee_t *bee = ic->bee;
+ bee_user_t *bu = NULL;
+
+ if( set_getbool( &bee->set, "debug" ) )
+ imcb_log( ic, "User %s removed from conversation %p (%s)", handle, c, reason ? reason : "" );
+
+ /* It might be yourself! */
+ if( g_strcasecmp( handle, ic->acc->user ) == 0 )
+ {
+ if( c->joined == 0 )
+ return;
+
+ bu = bee->user;
+ c->joined = 0;
+ }
+ else
+ {
+ bu = bee_user_by_handle( bee, ic, handle );
+ }
+
+ if( bee->ui->chat_remove_user )
+ bee->ui->chat_remove_user( bee, c, bu );
+}
+
+int bee_chat_msg( bee_t *bee, struct groupchat *c, const char *msg, int flags )
+{
+ struct im_connection *ic = c->ic;
+ char *buf = NULL;
+
+ if( ( ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )
+ {
+ buf = escape_html( msg );
+ msg = buf;
+ }
+ else
+ buf = g_strdup( msg );
+
+ ic->acc->prpl->chat_msg( c, buf, flags );
+ g_free( buf );
+
+ return 1;
+}
+
+struct groupchat *bee_chat_by_title( bee_t *bee, struct im_connection *ic, const char *title )
+{
+ struct groupchat *c;
+ GSList *l;
+
+ for( l = ic->groupchats; l; l = l->next )
+ {
+ c = l->data;
+ if( strcmp( c->title, title ) == 0 )
+ return c;
+ }
+
+ return NULL;
+}
diff --git a/protocols/bee_ft.c b/protocols/bee_ft.c
new file mode 100644
index 00000000..1026eab3
--- /dev/null
+++ b/protocols/bee_ft.c
@@ -0,0 +1,66 @@
+/********************************************************************\
+* BitlBee -- An IRC to other IM-networks gateway *
+* *
+* Copyright 2010 Wilmer van der Gaast <wilmer@gaast.net> *
+\********************************************************************/
+
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License with
+ the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+ Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#define BITLBEE_CORE
+#include "bitlbee.h"
+#include "ft.h"
+
+file_transfer_t *imcb_file_send_start( struct im_connection *ic, char *handle, char *file_name, size_t file_size )
+{
+ bee_t *bee = ic->bee;
+ bee_user_t *bu = bee_user_by_handle( bee, ic, handle );
+
+ if( bee->ui->ft_in_start )
+ return bee->ui->ft_in_start( bee, bu, file_name, file_size );
+ else
+ return NULL;
+}
+
+gboolean imcb_file_recv_start( struct im_connection *ic, file_transfer_t *ft )
+{
+ bee_t *bee = ic->bee;
+
+ if( bee->ui->ft_out_start )
+ return bee->ui->ft_out_start( ic, ft );
+ else
+ return FALSE;
+}
+
+void imcb_file_canceled( struct im_connection *ic, file_transfer_t *file, char *reason )
+{
+ bee_t *bee = ic->bee;
+
+ if( file->canceled )
+ file->canceled( file, reason );
+
+ if( bee->ui->ft_close )
+ bee->ui->ft_close( ic, file );
+}
+
+void imcb_file_finished( struct im_connection *ic, file_transfer_t *file )
+{
+ bee_t *bee = ic->bee;
+
+ if( bee->ui->ft_finished )
+ bee->ui->ft_finished( ic, file );
+}
diff --git a/protocols/bee_user.c b/protocols/bee_user.c
new file mode 100644
index 00000000..28235a6d
--- /dev/null
+++ b/protocols/bee_user.c
@@ -0,0 +1,246 @@
+ /********************************************************************\
+ * BitlBee -- An IRC to other IM-networks gateway *
+ * *
+ * Copyright 2002-2010 Wilmer van der Gaast and others *
+ \********************************************************************/
+
+/* Stuff to handle, save and search buddies */
+
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License with
+ the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+ Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#define BITLBEE_CORE
+#include "bitlbee.h"
+
+bee_user_t *bee_user_new( bee_t *bee, struct im_connection *ic, const char *handle, bee_user_flags_t flags )
+{
+ bee_user_t *bu;
+
+ if( bee_user_by_handle( bee, ic, handle ) != NULL )
+ return NULL;
+
+ bu = g_new0( bee_user_t, 1 );
+ bu->bee = bee;
+ bu->ic = ic;
+ bu->flags = flags;
+ bu->handle = g_strdup( handle );
+ bee->users = g_slist_prepend( bee->users, bu );
+
+ if( bee->ui->user_new )
+ bee->ui->user_new( bee, bu );
+
+ /* Offline by default. This will set the right flags. */
+ imcb_buddy_status( ic, handle, 0, NULL, NULL );
+
+ return bu;
+}
+
+int bee_user_free( bee_t *bee, bee_user_t *bu )
+{
+ if( !bu )
+ return 0;
+
+ if( bee->ui->user_free )
+ bee->ui->user_free( bee, bu );
+
+ g_free( bu->handle );
+ g_free( bu->fullname );
+ g_free( bu->status );
+ g_free( bu->status_msg );
+
+ bee->users = g_slist_remove( bee->users, bu );
+
+ return 1;
+}
+
+bee_user_t *bee_user_by_handle( bee_t *bee, struct im_connection *ic, const char *handle )
+{
+ GSList *l;
+
+ for( l = bee->users; l; l = l->next )
+ {
+ bee_user_t *bu = l->data;
+
+ if( bu->ic == ic && ic->acc->prpl->handle_cmp( bu->handle, handle ) == 0 )
+ return bu;
+ }
+
+ return NULL;
+}
+
+int bee_user_msg( bee_t *bee, bee_user_t *bu, const char *msg, int flags )
+{
+ char *buf = NULL;
+ int st;
+
+ if( ( bu->ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )
+ {
+ buf = escape_html( msg );
+ msg = buf;
+ }
+ else
+ buf = g_strdup( msg );
+
+ st = bu->ic->acc->prpl->buddy_msg( bu->ic, bu->handle, buf, flags );
+ g_free( buf );
+
+ return st;
+}
+
+
+/* Groups */
+static bee_group_t *bee_group_new( bee_t *bee, const char *name )
+{
+ bee_group_t *bg = g_new0( bee_group_t, 1 );
+
+ bg->name = g_strdup( name );
+ bg->key = g_utf8_casefold( name, -1 );
+ bee->groups = g_slist_prepend( bee->groups, bg );
+
+ return bg;
+}
+
+bee_group_t *bee_group_by_name( bee_t *bee, const char *name, gboolean creat )
+{
+ GSList *l;
+ char *key;
+
+ if( name == NULL )
+ return NULL;
+
+ key = g_utf8_casefold( name, -1 );
+ for( l = bee->groups; l; l = l->next )
+ {
+ bee_group_t *bg = l->data;
+ if( strcmp( bg->key, key ) == 0 )
+ break;
+ }
+ g_free( key );
+
+ if( !l )
+ return creat ? bee_group_new( bee, name ) : NULL;
+ else
+ return l->data;
+}
+
+void bee_group_free( bee_t *bee )
+{
+ while( bee->groups )
+ {
+ bee_group_t *bg = bee->groups->data;
+ g_free( bg->name );
+ g_free( bg->key );
+ g_free( bg );
+ bee->groups = g_slist_remove( bee->groups, bee->groups->data );
+ }
+}
+
+
+/* IM->UI callbacks */
+void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message )
+{
+ bee_t *bee = ic->bee;
+ bee_user_t *bu, *old;
+
+ if( !( bu = bee_user_by_handle( bee, ic, handle ) ) )
+ {
+ if( g_strcasecmp( set_getstr( &ic->bee->set, "handle_unknown" ), "add" ) == 0 )
+ {
+ bu = bee_user_new( bee, ic, handle, BEE_USER_LOCAL );
+ }
+ else
+ {
+ if( g_strcasecmp( set_getstr( &ic->bee->set, "handle_unknown" ), "ignore" ) != 0 )
+ {
+ imcb_log( ic, "imcb_buddy_status() for unknown handle %s:\n"
+ "flags = %d, state = %s, message = %s", handle, flags,
+ state ? state : "NULL", message ? message : "NULL" );
+ }
+
+ return;
+ }
+ }
+
+ /* May be nice to give the UI something to compare against. */
+ old = g_memdup( bu, sizeof( bee_user_t ) );
+
+ /* TODO(wilmer): OPT_AWAY, or just state == NULL ? */
+ bu->flags = flags;
+ bu->status = g_strdup( ( flags & OPT_AWAY ) && state == NULL ? "Away" : state );
+ bu->status_msg = g_strdup( message );
+
+ if( bee->ui->user_status )
+ bee->ui->user_status( bee, bu, old );
+
+ g_free( old->status_msg );
+ g_free( old->status );
+ g_free( old );
+}
+
+void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle )
+{
+ bee_t *bee = ic->bee;
+ bee_user_t *bu;
+
+ if( !( bu = bee_user_by_handle( bee, ic, handle ) ) )
+ return;
+
+ bu->login_time = login;
+ bu->idle_time = idle;
+}
+
+void imcb_buddy_msg( struct im_connection *ic, const char *handle, char *msg, uint32_t flags, time_t sent_at )
+{
+ bee_t *bee = ic->bee;
+ bee_user_t *bu;
+
+ bu = bee_user_by_handle( bee, ic, handle );
+
+ if( !bu )
+ {
+ char *h = set_getstr( &bee->set, "handle_unknown" );
+
+ if( g_strcasecmp( h, "ignore" ) == 0 )
+ {
+ return;
+ }
+ else if( g_strncasecmp( h, "add", 3 ) == 0 )
+ {
+ bu = bee_user_new( bee, ic, handle, BEE_USER_LOCAL );
+ }
+ }
+
+ if( ( g_strcasecmp( set_getstr( &ic->bee->set, "strip_html" ), "always" ) == 0 ) ||
+ ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->bee->set, "strip_html" ) ) )
+ strip_html( msg );
+
+ if( bee->ui->user_msg && bu )
+ bee->ui->user_msg( bee, bu, msg, sent_at );
+ else
+ imcb_log( ic, "Message from unknown handle %s:\n%s", handle, msg );
+}
+
+void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags )
+{
+ bee_user_t *bu;
+
+ if( ic->bee->ui->user_typing &&
+ ( bu = bee_user_by_handle( ic->bee, ic, handle ) ) )
+ {
+ ic->bee->ui->user_typing( ic->bee, bu, flags );
+ }
+}
diff --git a/protocols/chat.c b/protocols/chat.c
new file mode 100644
index 00000000..8c5ce0bc
--- /dev/null
+++ b/protocols/chat.c
@@ -0,0 +1,192 @@
+ /********************************************************************\
+ * BitlBee -- An IRC to other IM-networks gateway *
+ * *
+ * Copyright 2002-2008 Wilmer van der Gaast and others *
+ \********************************************************************/
+
+/* Keep track of chatrooms the user is interested in */
+
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License with
+ the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+ Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "bitlbee.h"
+#include "chat.h"
+
+struct chat *chat_add( irc_t *irc, account_t *acc, char *handle, char *channel )
+{
+ struct chat *c, *l;
+ set_t *s;
+
+ if( acc->prpl->chat_join == NULL || !chat_chanok( channel ) ||
+ chat_chancmp( channel, irc->channel ) == 0 )
+ {
+ return NULL;
+ }
+
+ for( c = irc->chatrooms; c; c = c->next )
+ {
+ if( chat_chancmp( channel, c->channel ) == 0 )
+ return NULL;
+
+ if( acc == c->acc && g_strcasecmp( handle, c->handle ) == 0 )
+ return NULL;
+
+ l = c;
+ }
+
+ if( irc->chatrooms == NULL )
+ irc->chatrooms = c = g_new0( struct chat, 1 );
+ else
+ l->next = c = g_new0( struct chat, 1 );
+
+ c->acc = acc;
+ c->handle = g_strdup( handle );
+ c->channel = g_strdup( channel );
+
+ s = set_add( &c->set, "auto_join", "false", set_eval_bool, c );
+ /* s = set_add( &c->set, "auto_rejoin", "false", set_eval_bool, c ); */
+ s = set_add( &c->set, "nick", NULL, NULL, c );
+ s->flags |= SET_NULL_OK;
+
+ return c;
+}
+
+struct chat *chat_byhandle( irc_t *irc, account_t *acc, char *handle )
+{
+ struct chat *c;
+
+ for( c = irc->chatrooms; c; c = c->next )
+ {
+ if( acc == c->acc && g_strcasecmp( handle, c->handle ) == 0 )
+ break;
+ }
+
+ return c;
+}
+
+struct chat *chat_bychannel( irc_t *irc, char *channel )
+{
+ struct chat *c;
+
+ for( c = irc->chatrooms; c; c = c->next )
+ {
+ if( chat_chancmp( channel, c->channel ) == 0 )
+ break;
+ }
+
+ return c;
+}
+
+struct chat *chat_get( irc_t *irc, char *id )
+{
+ struct chat *c, *ret = NULL;
+ int nr;
+
+ if( sscanf( id, "%d", &nr ) == 1 && nr < 1000 )
+ {
+ for( c = irc->chatrooms; c; c = c->next )
+ if( ( nr-- ) == 0 )
+ return c;
+
+ return NULL;
+ }
+
+ for( c = irc->chatrooms; c; c = c->next )
+ {
+ if( strstr( c->handle, id ) )
+ {
+ if( !ret )
+ ret = c;
+ else
+ return NULL;
+ }
+ else if( strstr( c->channel, id ) )
+ {
+ if( !ret )
+ ret = c;
+ else
+ return NULL;
+ }
+ }
+
+ return ret;
+}
+
+int chat_del( irc_t *irc, struct chat *chat )
+{
+ struct chat *c, *l = NULL;
+
+ for( c = irc->chatrooms; c; c = (l=c)->next )
+ if( c == chat )
+ break;
+
+ if( c == NULL )
+ return 0;
+ else if( l == NULL )
+ irc->chatrooms = c->next;
+ else
+ l->next = c->next;
+
+ while( c->set )
+ set_del( &c->set, c->set->key );
+
+ g_free( c->handle );
+ g_free( c->channel );
+ g_free( c );
+
+ return 1;
+}
+
+int chat_chancmp( char *a, char *b )
+{
+ if( !chat_chanok( a ) || !chat_chanok( b ) )
+ return 0;
+
+ if( a[0] == b[0] )
+ return nick_cmp( a + 1, b + 1 );
+ else
+ return -1;
+}
+
+int chat_chanok( char *a )
+{
+ if( strchr( CTYPES, a[0] ) != NULL )
+ return nick_ok( a + 1 );
+ else
+ return 0;
+}
+
+int chat_join( irc_t *irc, struct chat *c, const char *password )
+{
+ struct groupchat *gc;
+ char *nick = set_getstr( &c->set, "nick" );
+
+ if( c->acc->ic == NULL || c->acc->prpl->chat_join == NULL )
+ return 0;
+
+ if( nick == NULL )
+ nick = irc->nick;
+
+ if( ( gc = c->acc->prpl->chat_join( c->acc->ic, c->handle, nick, password ) ) )
+ {
+ g_free( gc->channel );
+ gc->channel = g_strdup( c->channel );
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/protocols/chat.h b/protocols/chat.h
new file mode 100644
index 00000000..7196aea8
--- /dev/null
+++ b/protocols/chat.h
@@ -0,0 +1,51 @@
+ /********************************************************************\
+ * BitlBee -- An IRC to other IM-networks gateway *
+ * *
+ * Copyright 2002-2008 Wilmer van der Gaast and others *
+ \********************************************************************/
+
+/* Keep track of chatrooms the user is interested in */
+
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License with
+ the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+ Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _CHAT_H
+#define _CHAT_H
+
+struct chat
+{
+ account_t *acc;
+
+ char *handle;
+ char *channel;
+ set_t *set;
+
+ struct chat *next;
+};
+
+struct chat *chat_add( irc_t *irc, account_t *acc, char *handle, char *channel );
+struct chat *chat_byhandle( irc_t *irc, account_t *acc, char *handle );
+struct chat *chat_bychannel( irc_t *irc, char *channel );
+struct chat *chat_get( irc_t *irc, char *id );
+int chat_del( irc_t *irc, struct chat *chat );
+
+int chat_chancmp( char *a, char *b );
+int chat_chanok( char *a );
+
+int chat_join( irc_t *irc, struct chat *c, const char *password );
+
+#endif
diff --git a/protocols/ft.h b/protocols/ft.h
index 1155f06f..159f16f2 100644
--- a/protocols/ft.h
+++ b/protocols/ft.h
@@ -106,6 +106,7 @@ typedef struct file_transfer {
* IM-protocol specific data associated with this file transfer.
*/
gpointer data;
+ struct im_connection *ic;
/*
* Private data.
@@ -167,9 +168,9 @@ file_transfer_t *imcb_file_send_start( struct im_connection *ic, char *user_nick
* This should be called by a protocol when the transfer is canceled. Note that
* the canceled() and free() callbacks given in file will be called by this function.
*/
-void imcb_file_canceled( file_transfer_t *file, char *reason );
+void imcb_file_canceled( struct im_connection *ic, file_transfer_t *file, char *reason );
-gboolean imcb_file_recv_start( file_transfer_t *ft );
+gboolean imcb_file_recv_start( struct im_connection *ic, file_transfer_t *ft );
-void imcb_file_finished( file_transfer_t *file );
+void imcb_file_finished( struct im_connection *ic, file_transfer_t *file );
#endif
diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c
index affe8aef..e04b9792 100644
--- a/protocols/jabber/conference.c
+++ b/protocols/jabber/conference.c
@@ -91,18 +91,20 @@ static xt_status jabber_chat_join_failed( struct im_connection *ic, struct xt_no
struct groupchat *jabber_chat_by_jid( struct im_connection *ic, const char *name )
{
char *normalized = jabber_normalize( name );
+ GSList *l;
struct groupchat *ret;
struct jabber_chat *jc;
- for( ret = ic->groupchats; ret; ret = ret->next )
+ for( l = ic->groupchats; l; l = l->next )
{
+ ret = l->data;
jc = ret->data;
if( strcmp( normalized, jc->name ) == 0 )
break;
}
g_free( normalized );
- return ret;
+ return l ? ret : NULL;
}
void jabber_chat_free( struct groupchat *c )
diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c
index 77c0d628..5166e322 100644
--- a/protocols/jabber/iq.c
+++ b/protocols/jabber/iq.c
@@ -381,7 +381,7 @@ static xt_status jabber_parse_roster( struct im_connection *ic, struct xt_node *
c = query->children;
while( ( c = xt_find_node( c, "item" ) ) )
{
- struct xt_node *group = xt_find_node( node->children, "group" );
+ struct xt_node *group = xt_find_node( c->children, "group" );
char *jid = xt_find_attr( c, "jid" );
char *name = xt_find_attr( c, "name" );
char *sub = xt_find_attr( c, "subscription" );
@@ -390,9 +390,8 @@ static xt_status jabber_parse_roster( struct im_connection *ic, struct xt_node *
{
if( ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) )
{
- if( initial || imcb_find_buddy( ic, jid ) == NULL )
- imcb_add_buddy( ic, jid, ( group && group->text_len ) ?
- group->text : NULL );
+ imcb_add_buddy( ic, jid, ( group && group->text_len ) ?
+ group->text : NULL );
if( name )
imcb_rename_buddy( ic, jid, name );
@@ -588,7 +587,7 @@ static xt_status jabber_add_to_roster_callback( struct im_connection *ic, struct
( s = xt_find_attr( node, "type" ) ) &&
strcmp( s, "result" ) == 0 )
{
- if( imcb_find_buddy( ic, jid ) == NULL )
+ if( bee_user_by_handle( ic->bee, ic, jid ) == NULL )
imcb_add_buddy( ic, jid, NULL );
}
else
diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c
index 956769b7..75bc44d3 100644
--- a/protocols/jabber/jabber.c
+++ b/protocols/jabber/jabber.c
@@ -266,7 +266,7 @@ static void jabber_logout( struct im_connection *ic )
struct jabber_data *jd = ic->proto_data;
while( jd->filetransfers )
- imcb_file_canceled( ( ( struct jabber_transfer *) jd->filetransfers->data )->ft, "Logging out" );
+ imcb_file_canceled( ic, ( ( struct jabber_transfer *) jd->filetransfers->data )->ft, "Logging out" );
while( jd->streamhosts )
{
@@ -281,7 +281,7 @@ static void jabber_logout( struct im_connection *ic )
jabber_end_stream( ic );
while( ic->groupchats )
- jabber_chat_free( ic->groupchats );
+ jabber_chat_free( ic->groupchats->data );
if( jd->r_inpa >= 0 )
b_event_remove( jd->r_inpa );
diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c
index 4bc9e3a8..608cb52a 100644
--- a/protocols/jabber/jabber_util.c
+++ b/protocols/jabber/jabber_util.c
@@ -278,8 +278,7 @@ static void jabber_buddy_ask_yes( void *data )
presence_send_request( bla->ic, bla->handle, "subscribed" );
- if( imcb_find_buddy( bla->ic, bla->handle ) == NULL )
- imcb_ask_add( bla->ic, bla->handle, NULL );
+ imcb_ask_add( bla->ic, bla->handle, NULL );
g_free( bla->handle );
g_free( bla );
@@ -461,7 +460,7 @@ struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid_,
}
if( bud == NULL && ( flags & GET_BUDDY_CREAT ) &&
- ( bare_exists || imcb_find_buddy( ic, jid ) ) )
+ ( bare_exists || bee_user_by_handle( ic->bee, ic, jid ) ) )
{
*s = '/';
bud = jabber_buddy_add( ic, jid );
@@ -482,7 +481,8 @@ struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid_,
if( bud == NULL )
/* No match. Create it now? */
- return ( ( flags & GET_BUDDY_CREAT ) && imcb_find_buddy( ic, jid_ ) ) ?
+ return ( ( flags & GET_BUDDY_CREAT ) &&
+ bee_user_by_handle( ic->bee, ic, jid_ ) ) ?
jabber_buddy_add( ic, jid_ ) : NULL;
else if( bud->resource && ( flags & GET_BUDDY_EXACT ) )
/* We want an exact match, so in thise case there shouldn't be a /resource. */
diff --git a/protocols/jabber/presence.c b/protocols/jabber/presence.c
index 006eeead..2875d23e 100644
--- a/protocols/jabber/presence.c
+++ b/protocols/jabber/presence.c
@@ -204,7 +204,7 @@ int presence_send_update( struct im_connection *ic )
{
struct jabber_data *jd = ic->proto_data;
struct xt_node *node, *cap;
- struct groupchat *c;
+ GSList *l;
int st;
node = jabber_make_packet( "presence", NULL, NULL, NULL );
@@ -228,8 +228,9 @@ int presence_send_update( struct im_connection *ic )
/* Have to send this update to all groupchats too, the server won't
do this automatically. */
- for( c = ic->groupchats; c && st; c = c->next )
+ for( l = ic->groupchats; l && st; l = l->next )
{
+ struct groupchat *c = l->data;
struct jabber_chat *jc = c->data;
xt_add_attr( node, "to", jc->my_full_jid );
diff --git a/protocols/jabber/s5bytestream.c b/protocols/jabber/s5bytestream.c
index 19d0d81a..a8137271 100644
--- a/protocols/jabber/s5bytestream.c
+++ b/protocols/jabber/s5bytestream.c
@@ -566,7 +566,7 @@ gboolean jabber_bs_recv_handshake_abort( struct bs_transfer *bt, char *error )
imcb_log( tf->ic, "WARNING: Error transmitting bytestream response" );
xt_free_node( reply );
- imcb_file_canceled( tf->ft, "couldn't connect to any streamhosts" );
+ imcb_file_canceled( tf->ic, tf->ft, "couldn't connect to any streamhosts" );
bt->tf->watch_in = 0;
/* MUST always return FALSE! */
@@ -603,7 +603,7 @@ void jabber_bs_recv_answer_request( struct bs_transfer *bt )
xt_add_attr( reply, "id", tf->iq_id );
if( !jabber_write_packet( tf->ic, reply ) )
- imcb_file_canceled( tf->ft, "Error transmitting bytestream response" );
+ imcb_file_canceled( tf->ic, tf->ft, "Error transmitting bytestream response" );
xt_free_node( reply );
}
@@ -643,7 +643,7 @@ gboolean jabber_bs_recv_read( gpointer data, gint fd, b_input_condition cond )
tf->bytesread += ret;
if( tf->bytesread >= tf->ft->file_size )
- imcb_file_finished( tf->ft );
+ imcb_file_finished( tf->ic, tf->ft );
tf->ft->write( tf->ft, tf->ft->buffer, ret );
@@ -659,7 +659,7 @@ gboolean jabber_bs_recv_write_request( file_transfer_t *ft )
if( tf->watch_in )
{
- imcb_file_canceled( ft, "BUG in jabber file transfer: write_request called when already watching for input" );
+ imcb_file_canceled( tf->ic, ft, "BUG in jabber file transfer: write_request called when already watching for input" );
return FALSE;
}
@@ -705,7 +705,7 @@ gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, unsigned int l
return jabber_bs_abort( bt, "send() sent %d instead of %d (send buffer too big!)", ret, len );
if( tf->byteswritten >= ft->file_size )
- imcb_file_finished( ft );
+ imcb_file_finished( tf->ic, ft );
else
bt->tf->watch_out = b_input_add( tf->fd, B_EV_IO_WRITE, jabber_bs_send_can_write, bt );
@@ -1005,7 +1005,7 @@ gboolean jabber_bs_send_request( struct jabber_transfer *tf, GSList *streamhosts
jabber_cache_add( tf->ic, iq, jabber_bs_send_handle_reply );
if( !jabber_write_packet( tf->ic, iq ) )
- imcb_file_canceled( tf->ft, "Error transmitting bytestream request" );
+ imcb_file_canceled( tf->ic, tf->ft, "Error transmitting bytestream request" );
return TRUE;
}
@@ -1020,7 +1020,7 @@ gboolean jabber_bs_send_handshake_abort(struct bs_transfer *bt, char *error )
error );
if( jd->streamhosts==NULL ) /* we're done here unless we have a proxy to try */
- imcb_file_canceled( tf->ft, error );
+ imcb_file_canceled( tf->ic, tf->ft, error );
/* MUST always return FALSE! */
return FALSE;
diff --git a/protocols/jabber/si.c b/protocols/jabber/si.c
index bfb64f11..58c0e17f 100644
--- a/protocols/jabber/si.c
+++ b/protocols/jabber/si.c
@@ -90,11 +90,11 @@ int jabber_si_check_features( struct jabber_transfer *tf, GSList *features ) {
}
if( !foundft )
- imcb_file_canceled( tf->ft, "Buddy's client doesn't feature file transfers" );
+ imcb_file_canceled( tf->ic, tf->ft, "Buddy's client doesn't feature file transfers" );
else if( !foundbt )
- imcb_file_canceled( tf->ft, "Buddy's client doesn't feature byte streams (required)" );
+ imcb_file_canceled( tf->ic, tf->ft, "Buddy's client doesn't feature byte streams (required)" );
else if( !foundsi )
- imcb_file_canceled( tf->ft, "Buddy's client doesn't feature stream initiation (required)" );
+ imcb_file_canceled( tf->ic, tf->ft, "Buddy's client doesn't feature stream initiation (required)" );
return foundft && foundbt && foundsi;
}
@@ -108,7 +108,7 @@ void jabber_si_transfer_start( struct jabber_transfer *tf ) {
jabber_si_send_request( tf->ic, tf->bud->full_jid, tf );
/* and start the receive logic */
- imcb_file_recv_start( tf->ft );
+ imcb_file_recv_start( tf->ic, tf->ft );
}
@@ -155,7 +155,7 @@ void jabber_si_transfer_request( struct im_connection *ic, file_transfer_t *ft,
if( bud == NULL )
{
- imcb_file_canceled( ft, "Couldn't find buddy (BUG?)" );
+ imcb_file_canceled( ic, ft, "Couldn't find buddy (BUG?)" );
return;
}
diff --git a/protocols/msn/Makefile b/protocols/msn/Makefile
index 1de755a8..6c59aedb 100644
--- a/protocols/msn/Makefile
+++ b/protocols/msn/Makefile
@@ -12,7 +12,7 @@ SRCDIR := $(SRCDIR)protocols/msn/
endif
# [SH] Program variables
-objects = invitation.o msn.o msn_util.o ns.o passport.o sb.o tables.o
+objects = msn.o msn_util.o ns.o passport.o sb.o tables.o
CFLAGS += -Wall
LFLAGS += -r
diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c
index 0d67cc17..d6a4b158 100644
--- a/protocols/msn/msn.c
+++ b/protocols/msn/msn.c
@@ -78,9 +78,11 @@ static void msn_logout( struct im_connection *ic )
if( md )
{
+ /** Disabling MSN ft support for now.
while( md->filetransfers ) {
imcb_file_canceled( md->filetransfers->data, "Closing connection" );
}
+ */
if( md->fd >= 0 )
closesocket( md->fd );
@@ -220,6 +222,7 @@ static void msn_chat_leave( struct groupchat *c )
static struct groupchat *msn_chat_with( struct im_connection *ic, char *who )
{
struct msn_switchboard *sb;
+ struct groupchat *c = imcb_chat_new( ic, who );
if( ( sb = msn_sb_by_handle( ic, who ) ) )
{
@@ -237,10 +240,8 @@ static struct groupchat *msn_chat_with( struct im_connection *ic, char *who )
msn_sb_write_msg( ic, m );
- return NULL;
+ return c;
}
-
- return NULL;
}
static void msn_keepalive( struct im_connection *ic )
@@ -331,7 +332,7 @@ void msn_initmodule()
ret->rem_deny = msn_rem_deny;
ret->send_typing = msn_send_typing;
ret->handle_cmp = g_strcasecmp;
- ret->transfer_request = msn_ftp_transfer_request;
+ //ret->transfer_request = msn_ftp_transfer_request;
register_protocol(ret);
}
diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c
index 9c9d2720..a8d24b30 100644
--- a/protocols/msn/msn_util.c
+++ b/protocols/msn/msn_util.c
@@ -95,8 +95,7 @@ static void msn_buddy_ask_yes( void *data )
msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname );
- if( imcb_find_buddy( bla->ic, bla->handle ) == NULL )
- imcb_ask_add( bla->ic, bla->handle, NULL );
+ imcb_ask_add( bla->ic, bla->handle, NULL );
g_free( bla->handle );
g_free( bla->realname );
diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c
index 1614f69f..cb5789b8 100644
--- a/protocols/msn/sb.c
+++ b/protocols/msn/sb.c
@@ -174,14 +174,14 @@ int msn_sb_sendmessage( struct msn_switchboard *sb, char *text )
buf = g_new0( char, i );
i = g_snprintf( buf, i, MSN_TYPING_HEADERS, sb->ic->acc->user );
}
- else if( strncmp( text, MSN_INVITE_HEADERS, sizeof( MSN_INVITE_HEADERS ) - 1 ) == 0 )
+ else if( strcmp( text, SB_KEEPALIVE_MESSAGE ) == 0 )
{
- buf = g_strdup( text );
+ buf = g_strdup( SB_KEEPALIVE_HEADERS );
i = strlen( buf );
}
- else if( strcmp( text, SB_KEEPALIVE_MESSAGE ) == 0 )
+ else if( strncmp( text, MSN_INVITE_HEADERS, sizeof( MSN_INVITE_HEADERS ) - 1 ) == 0 )
{
- buf = g_strdup( SB_KEEPALIVE_HEADERS );
+ buf = g_strdup( text );
i = strlen( buf );
}
else
@@ -232,11 +232,17 @@ int msn_sb_sendmessage( struct msn_switchboard *sb, char *text )
struct groupchat *msn_sb_to_chat( struct msn_switchboard *sb )
{
struct im_connection *ic = sb->ic;
+ struct groupchat *c = NULL;
char buf[1024];
/* Create the groupchat structure. */
g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session );
- sb->chat = imcb_chat_new( ic, buf );
+ if( sb->who )
+ c = bee_chat_by_title( ic->bee, ic, sb->who );
+ if( c && !msn_sb_by_chat( c ) )
+ sb->chat = c;
+ else
+ sb->chat = imcb_chat_new( ic, buf );
/* Populate the channel. */
if( sb->who ) imcb_chat_add_buddy( sb->chat, sb->who );
@@ -697,6 +703,8 @@ static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int
/* PANIC! */
}
}
+#if 0
+ // Disable MSN ft support for now.
else if( g_strncasecmp( ct, "text/x-msmsgsinvite", 19 ) == 0 )
{
char *command = msn_findheader( body, "Invitation-Command:", blen );
@@ -729,6 +737,7 @@ static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int
g_free( command );
}
+#endif
else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 )
{
imcb_error( sb->ic, "Cannot receive file from %s: BitlBee does not "
@@ -764,10 +773,11 @@ static gboolean msn_sb_keepalive( gpointer data, gint source, b_input_condition
void msn_sb_start_keepalives( struct msn_switchboard *sb, gboolean initial )
{
- struct buddy *b;
+ bee_user_t *bu;
if( sb && sb->who && sb->keepalive == 0 &&
- ( b = imcb_find_buddy( sb->ic, sb->who ) ) && !b->present &&
+ ( bu = bee_user_by_handle( sb->ic->bee, sb->ic, sb->who ) ) &&
+ !( bu->flags & BEE_USER_ONLINE ) &&
set_getbool( &sb->ic->acc->set, "switchboard_keepalives" ) )
{
if( initial )
diff --git a/protocols/nogaim.c b/protocols/nogaim.c
index cd57a289..6ecdfe12 100644
--- a/protocols/nogaim.c
+++ b/protocols/nogaim.c
@@ -37,9 +37,6 @@
#include "nogaim.h"
#include "chat.h"
-static int remove_chat_buddy_silent( struct groupchat *b, const char *handle );
-static char *format_timestamp( irc_t *irc, time_t msg_ts );
-
GSList *connections;
#ifdef WITH_PLUGINS
@@ -92,8 +89,6 @@ void load_plugins(void)
}
#endif
-/* nogaim.c */
-
GList *protocols = NULL;
void register_protocol (struct prpl *p)
@@ -128,7 +123,6 @@ struct prpl *find_protocol(const char *name)
return NULL;
}
-/* nogaim.c */
void nogaim_init()
{
extern void msn_initmodule();
@@ -157,7 +151,7 @@ void nogaim_init()
#ifdef WITH_TWITTER
twitter_initmodule();
#endif
-
+
#ifdef WITH_PURPLE
purple_initmodule();
#endif
@@ -169,15 +163,13 @@ void nogaim_init()
GSList *get_connections() { return connections; }
-/* multi.c */
-
struct im_connection *imcb_new( account_t *acc )
{
struct im_connection *ic;
ic = g_new0( struct im_connection, 1 );
- ic->irc = acc->irc;
+ ic->bee = acc->bee;
ic->acc = acc;
acc->ic = ic;
@@ -191,7 +183,7 @@ void imc_free( struct im_connection *ic )
account_t *a;
/* Destroy the pointer to this connection from the account list */
- for( a = ic->irc->accounts; a; a = a->next )
+ for( a = ic->bee->accounts; a; a = a->next )
if( a->ic == ic )
{
a->ic = NULL;
@@ -212,20 +204,21 @@ static void serv_got_crap( struct im_connection *ic, char *format, ... )
text = g_strdup_vprintf( format, params );
va_end( params );
- if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
- ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
+ if( ( g_strcasecmp( set_getstr( &ic->bee->set, "strip_html" ), "always" ) == 0 ) ||
+ ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->bee->set, "strip_html" ) ) )
strip_html( text );
/* Try to find a different connection on the same protocol. */
- for( a = ic->irc->accounts; a; a = a->next )
+ for( a = ic->bee->accounts; a; a = a->next )
if( a->prpl == ic->acc->prpl && a->ic != ic )
break;
/* If we found one, include the screenname in the message. */
if( a )
- irc_usermsg( ic->irc, "%s(%s) - %s", ic->acc->prpl->name, ic->acc->user, text );
+ /* FIXME(wilmer): ui_log callback or so */
+ irc_usermsg( ic->bee->ui_data, "%s(%s) - %s", ic->acc->prpl->name, ic->acc->user, text );
else
- irc_usermsg( ic->irc, "%s - %s", ic->acc->prpl->name, text );
+ irc_usermsg( ic->bee->ui_data, "%s - %s", ic->acc->prpl->name, text );
g_free( text );
}
@@ -276,18 +269,12 @@ static gboolean send_keepalive( gpointer d, gint fd, b_input_condition cond )
void imcb_connected( struct im_connection *ic )
{
- irc_t *irc = ic->irc;
- struct chat *c;
- user_t *u;
-
/* MSN servers sometimes redirect you to a different server and do
the whole login sequence again, so these "late" calls to this
function should be handled correctly. (IOW, ignored) */
if( ic->flags & OPT_LOGGED_IN )
return;
- u = user_find( ic->irc, ic->irc->nick );
-
imcb_log( ic, "Logged in" );
ic->keepalive = b_timeout_add( 60000, send_keepalive, ic );
@@ -300,6 +287,7 @@ void imcb_connected( struct im_connection *ic )
exponential backoff timer. */
ic->acc->auto_reconnect_delay = 0;
+ /*
for( c = irc->chatrooms; c; c = c->next )
{
if( c->acc != ic->acc )
@@ -308,6 +296,7 @@ void imcb_connected( struct im_connection *ic )
if( set_getbool( &c->set, "auto_join" ) )
chat_join( irc, c, NULL );
}
+ */
}
gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond )
@@ -315,7 +304,7 @@ gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond )
account_t *a = data;
a->reconnect = 0;
- account_on( a->irc, a );
+ account_on( a->bee, a );
return( FALSE ); /* Only have to run the timeout once */
}
@@ -328,9 +317,9 @@ void cancel_auto_reconnect( account_t *a )
void imc_logout( struct im_connection *ic, int allow_reconnect )
{
- irc_t *irc = ic->irc;
- user_t *t, *u;
+ bee_t *bee = ic->bee;
account_t *a;
+ GSList *l;
int delay;
/* Nested calls might happen sometimes, this is probably the best
@@ -350,22 +339,20 @@ void imc_logout( struct im_connection *ic, int allow_reconnect )
g_free( ic->away );
ic->away = NULL;
- u = irc->users;
- while( u )
+ for( l = bee->users; l; )
{
- if( u->ic == ic )
- {
- t = u->next;
- user_del( irc, u->nick );
- u = t;
- }
- else
- u = u->next;
+ bee_user_t *bu = l->data;
+ GSList *next = l->next;
+
+ if( bu->ic == ic )
+ bee_user_free( bee, bu );
+
+ l = next;
}
- query_del_by_conn( ic->irc, ic );
+ query_del_by_conn( (irc_t*) ic->bee->ui_data, ic );
- for( a = irc->accounts; a; a = a->next )
+ for( a = bee->accounts; a; a = a->next )
if( a->ic == ic )
break;
@@ -373,7 +360,7 @@ void imc_logout( struct im_connection *ic, int allow_reconnect )
{
/* Uhm... This is very sick. */
}
- else if( allow_reconnect && set_getbool( &irc->set, "auto_reconnect" ) &&
+ else if( allow_reconnect && set_getbool( &bee->set, "auto_reconnect" ) &&
set_getbool( &a->set, "auto_reconnect" ) &&
( delay = account_reconnect_delay( a ) ) > 0 )
{
@@ -384,170 +371,59 @@ void imc_logout( struct im_connection *ic, int allow_reconnect )
imc_free( ic );
}
-
-/* dialogs.c */
-
void imcb_ask( struct im_connection *ic, char *msg, void *data,
query_callback doit, query_callback dont )
{
- query_add( ic->irc, ic, msg, doit, dont, data );
+ query_add( (irc_t *) ic->bee->ui_data, ic, msg, doit, dont, data );
}
-
-/* list.c */
-
void imcb_add_buddy( struct im_connection *ic, const char *handle, const char *group )
{
- user_t *u;
- char nick[MAX_NICK_LENGTH+1], *s;
- irc_t *irc = ic->irc;
-
- if( user_findhandle( ic, handle ) )
- {
- if( set_getbool( &irc->set, "debug" ) )
- imcb_log( ic, "User already exists, ignoring add request: %s", handle );
-
- return;
-
- /* Buddy seems to exist already. Let's ignore this request then...
- Eventually subsequent calls to this function *should* be possible
- when a buddy is in multiple groups. But for now BitlBee doesn't
- even support groups so let's silently ignore this for now. */
- }
-
- memset( nick, 0, MAX_NICK_LENGTH + 1 );
- strcpy( nick, nick_get( ic->acc, handle ) );
-
- u = user_add( ic->irc, nick );
-
-// if( !realname || !*realname ) realname = nick;
-// u->realname = g_strdup( realname );
-
- if( ( s = strchr( handle, '@' ) ) )
- {
- u->host = g_strdup( s + 1 );
- u->user = g_strndup( handle, s - handle );
- }
- else if( ic->acc->server )
- {
- u->host = g_strdup( ic->acc->server );
- u->user = g_strdup( handle );
-
- /* s/ /_/ ... important for AOL screennames */
- for( s = u->user; *s; s ++ )
- if( *s == ' ' )
- *s = '_';
- }
- else
- {
- u->host = g_strdup( ic->acc->prpl->name );
- u->user = g_strdup( handle );
- }
-
- u->ic = ic;
- u->handle = g_strdup( handle );
- if( group ) u->group = g_strdup( group );
- u->send_handler = buddy_send_handler;
- u->last_typing_notice = 0;
-}
-
-struct buddy *imcb_find_buddy( struct im_connection *ic, char *handle )
-{
- static struct buddy b[1];
- user_t *u;
-
- u = user_findhandle( ic, handle );
+ bee_user_t *bu;
+ bee_t *bee = ic->bee;
- if( !u )
- return( NULL );
+ if( !( bu = bee_user_by_handle( bee, ic, handle ) ) )
+ bu = bee_user_new( bee, ic, handle, 0 );
- memset( b, 0, sizeof( b ) );
- strncpy( b->name, handle, 80 );
- strncpy( b->show, u->realname, BUDDY_ALIAS_MAXLEN );
- b->present = u->online;
- b->ic = u->ic;
+ bu->group = bee_group_by_name( bee, group, TRUE );
- return( b );
+ if( bee->ui->user_group )
+ bee->ui->user_group( bee, bu );
}
-void imcb_rename_buddy( struct im_connection *ic, const char *handle, const char *realname )
+void imcb_rename_buddy( struct im_connection *ic, const char *handle, const char *fullname )
{
- user_t *u = user_findhandle( ic, handle );
- char *set;
-
- if( !u || !realname ) return;
+ bee_t *bee = ic->bee;
+ bee_user_t *bu = bee_user_by_handle( bee, ic, handle );
- if( g_strcasecmp( u->realname, realname ) != 0 )
- {
- if( u->realname != u->nick ) g_free( u->realname );
-
- u->realname = g_strdup( realname );
-
- if( ( ic->flags & OPT_LOGGED_IN ) && set_getbool( &ic->irc->set, "display_namechanges" ) )
- imcb_log( ic, "User `%s' changed name to `%s'", u->nick, u->realname );
- }
+ if( !bu || !fullname ) return;
- set = set_getstr( &ic->acc->set, "nick_source" );
- if( strcmp( set, "handle" ) != 0 )
+ if( !bu->fullname || strcmp( bu->fullname, fullname ) != 0 )
{
- char *name = g_strdup( realname );
-
- if( strcmp( set, "first_name" ) == 0 )
- {
- int i;
- for( i = 0; name[i] && !isspace( name[i] ); i ++ ) {}
- name[i] = '\0';
- }
-
- imcb_buddy_nick_hint( ic, handle, name );
+ g_free( bu->fullname );
+ bu->fullname = g_strdup( fullname );
- g_free( name );
+ if( bee->ui->user_fullname )
+ bee->ui->user_fullname( bee, bu );
}
}
void imcb_remove_buddy( struct im_connection *ic, const char *handle, char *group )
{
- user_t *u;
-
- if( ( u = user_findhandle( ic, handle ) ) )
- user_del( ic->irc, u->nick );
+ bee_user_free( ic->bee, bee_user_by_handle( ic->bee, ic, handle ) );
}
/* Mainly meant for ICQ (and now also for Jabber conferences) to allow IM
modules to suggest a nickname for a handle. */
void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick )
{
- user_t *u = user_findhandle( ic, handle );
- char newnick[MAX_NICK_LENGTH+1], *orig_nick;
+ bee_t *bee = ic->bee;
+ bee_user_t *bu = bee_user_by_handle( bee, ic, handle );
- if( u && !u->online && !nick_saved( ic->acc, handle ) )
- {
- /* Only do this if the person isn't online yet (which should
- be the case if we just added it) and if the user hasn't
- assigned a nickname to this buddy already. */
-
- strncpy( newnick, nick, MAX_NICK_LENGTH );
- newnick[MAX_NICK_LENGTH] = 0;
-
- /* Some processing to make sure this string is a valid IRC nickname. */
- nick_strip( newnick );
- if( set_getbool( &ic->irc->set, "lcnicks" ) )
- nick_lc( newnick );
-
- if( strcmp( u->nick, newnick ) != 0 )
- {
- /* Only do this if newnick is different from the current one.
- If rejoining a channel, maybe we got this nick already
- (and dedupe would only add an underscore. */
- nick_dedupe( ic->acc, handle, newnick );
-
- /* u->nick will be freed halfway the process, so it can't be
- passed as an argument. */
- orig_nick = g_strdup( u->nick );
- user_rename( ic->irc, orig_nick, newnick );
- g_free( orig_nick );
- }
- }
+ if( !bu || !nick ) return;
+
+ if( bee->ui->user_nick_hint )
+ bee->ui->user_nick_hint( bee, bu, nick );
}
@@ -592,7 +468,8 @@ void imcb_ask_auth( struct im_connection *ic, const char *handle, const char *re
data->ic = ic;
data->handle = g_strdup( handle );
- query_add( ic->irc, ic, s, imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, data );
+ query_add( (irc_t *) ic->bee->ui_data, ic, s,
+ imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, data );
}
@@ -617,672 +494,25 @@ void imcb_ask_add( struct im_connection *ic, const char *handle, const char *rea
char *s;
/* TODO: Make a setting for this! */
- if( user_findhandle( ic, handle ) != NULL )
+ if( bee_user_by_handle( ic->bee, ic, handle ) != NULL )
return;
s = g_strdup_printf( "The user %s is not in your buddy list yet. Do you want to add him/her now?", handle );
data->ic = ic;
data->handle = g_strdup( handle );
- query_add( ic->irc, ic, s, imcb_ask_add_cb_yes, imcb_ask_add_cb_no, data );
-}
-
-
-/* server.c */
-
-void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message )
-{
- user_t *u;
- int oa, oo;
-
- u = user_findhandle( ic, (char*) handle );
-
- if( !u )
- {
- if( g_strcasecmp( set_getstr( &ic->irc->set, "handle_unknown" ), "add" ) == 0 )
- {
- imcb_add_buddy( ic, (char*) handle, NULL );
- u = user_findhandle( ic, (char*) handle );
- }
- else
- {
- if( set_getbool( &ic->irc->set, "debug" ) || g_strcasecmp( set_getstr( &ic->irc->set, "handle_unknown" ), "ignore" ) != 0 )
- {
- imcb_log( ic, "imcb_buddy_status() for unknown handle %s:", handle );
- imcb_log( ic, "flags = %d, state = %s, message = %s", flags,
- state ? state : "NULL", message ? message : "NULL" );
- }
-
- return;
- }
- }
-
- oa = u->away != NULL;
- oo = u->online;
-
- g_free( u->away );
- g_free( u->status_msg );
- u->away = u->status_msg = NULL;
-
- if( set_getbool( &ic->irc->set, "show_offline" ) && !u->online )
- {
- /* always set users as online */
- irc_spawn( ic->irc, u );
- u->online = 1;
- if( !( flags & OPT_LOGGED_IN ) )
- {
- /* set away message if user isn't really online */
- u->away = g_strdup( "User is offline" );
- }
- }
- else if( ( flags & OPT_LOGGED_IN ) && !u->online )
- {
- irc_spawn( ic->irc, u );
- u->online = 1;
- }
- else if( !( flags & OPT_LOGGED_IN ) && u->online )
- {
- struct groupchat *c;
-
- if( set_getbool( &ic->irc->set, "show_offline" ) )
- {
- /* keep offline users in channel and set away message to "offline" */
- u->away = g_strdup( "User is offline" );
-
- /* Keep showing him/her in the control channel but not in groupchats. */
- for( c = ic->groupchats; c; c = c->next )
- {
- if( remove_chat_buddy_silent( c, handle ) && c->joined )
- irc_part( c->ic->irc, u, c->channel );
- }
- }
- else
- {
- /* kill offline users */
- irc_kill( ic->irc, u );
- u->online = 0;
-
- /* Remove him/her from the groupchats to prevent PART messages after he/she QUIT already */
- for( c = ic->groupchats; c; c = c->next )
- remove_chat_buddy_silent( c, handle );
- }
- }
-
- if( flags & OPT_AWAY )
- {
- if( state && message )
- {
- u->away = g_strdup_printf( "%s (%s)", state, message );
- }
- else if( state )
- {
- u->away = g_strdup( state );
- }
- else if( message )
- {
- u->away = g_strdup( message );
- }
- else
- {
- u->away = g_strdup( "Away" );
- }
- }
- else
- {
- u->status_msg = g_strdup( message );
- }
-
- /* early if-clause for show_offline even if there is some redundant code here because this isn't LISP but C ;) */
- if( set_getbool( &ic->irc->set, "show_offline" ) && set_getbool( &ic->irc->set, "away_devoice" ) )
- {
- char *from;
-
- if( set_getbool( &ic->irc->set, "simulate_netsplit" ) )
- {
- from = g_strdup( ic->irc->myhost );
- }
- else
- {
- from = g_strdup_printf( "%s!%s@%s", ic->irc->mynick, ic->irc->mynick,
- ic->irc->myhost );
- }
-
- /* if we use show_offline, we op online users, voice away users, and devoice/deop offline users */
- if( flags & OPT_LOGGED_IN )
- {
- /* user is "online" (either really online or away) */
- irc_write( ic->irc, ":%s MODE %s %cv%co %s %s", from, ic->irc->channel,
- u->away?'+':'-', u->away?'-':'+', u->nick, u->nick );
- }
- else
- {
- /* user is offline */
- irc_write( ic->irc, ":%s MODE %s -vo %s %s", from, ic->irc->channel, u->nick, u->nick );
- }
- }
- else
- {
- /* 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 */
- {
- char *from;
-
- if( set_getbool( &ic->irc->set, "simulate_netsplit" ) )
- {
- from = g_strdup( ic->irc->myhost );
- }
- else
- {
- 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 );
- g_free( from );
- }
- }
-}
-
-void imcb_buddy_msg( struct im_connection *ic, const char *handle, char *msg, uint32_t flags, time_t sent_at )
-{
- irc_t *irc = ic->irc;
- char *wrapped, *ts = NULL;
- user_t *u;
-
- u = user_findhandle( ic, handle );
-
- if( !u )
- {
- char *h = set_getstr( &irc->set, "handle_unknown" );
-
- if( g_strcasecmp( h, "ignore" ) == 0 )
- {
- if( set_getbool( &irc->set, "debug" ) )
- imcb_log( ic, "Ignoring message from unknown handle %s", handle );
-
- return;
- }
- else if( g_strncasecmp( h, "add", 3 ) == 0 )
- {
- int private = set_getbool( &irc->set, "private" );
-
- if( h[3] )
- {
- if( g_strcasecmp( h + 3, "_private" ) == 0 )
- private = 1;
- else if( g_strcasecmp( h + 3, "_channel" ) == 0 )
- private = 0;
- }
-
- imcb_add_buddy( ic, handle, NULL );
- u = user_findhandle( ic, handle );
- u->is_private = private;
- }
- else
- {
- imcb_log( ic, "Message from unknown handle %s:", handle );
- u = user_find( irc, irc->mynick );
- }
- }
-
- if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
- ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
- strip_html( msg );
-
- if( set_getbool( &ic->irc->set, "display_timestamps" ) &&
- ( ts = format_timestamp( irc, sent_at ) ) )
- {
- char *new = g_strconcat( ts, msg, NULL );
- g_free( ts );
- ts = msg = new;
- }
-
- wrapped = word_wrap( msg, 425 );
- irc_msgfrom( irc, u->nick, wrapped );
- g_free( wrapped );
- g_free( ts );
+ query_add( (irc_t *) ic->bee->ui_data, ic, s,
+ imcb_ask_add_cb_yes, imcb_ask_add_cb_no, data );
}
-void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags )
+struct bee_user *imcb_buddy_by_handle( struct im_connection *ic, const char *handle )
{
- user_t *u;
-
- if( !set_getbool( &ic->irc->set, "typing_notice" ) )
- return;
-
- if( ( u = user_findhandle( ic, handle ) ) )
- {
- char buf[256];
-
- g_snprintf( buf, 256, "\1TYPING %d\1", ( flags >> 8 ) & 3 );
- irc_privmsg( ic->irc, u, "PRIVMSG", ic->irc->nick, NULL, buf );
- }
-}
-
-struct groupchat *imcb_chat_new( struct im_connection *ic, const char *handle )
-{
- struct groupchat *c;
-
- /* This one just creates the conversation structure, user won't see anything yet */
-
- if( ic->groupchats )
- {
- for( c = ic->groupchats; c->next; c = c->next );
- c = c->next = g_new0( struct groupchat, 1 );
- }
- else
- ic->groupchats = c = g_new0( struct groupchat, 1 );
-
- c->ic = ic;
- c->title = g_strdup( handle );
- c->channel = g_strdup_printf( "&chat_%03d", ic->irc->c_id++ );
- c->topic = g_strdup_printf( "BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!", c->title );
-
- if( set_getbool( &ic->irc->set, "debug" ) )
- imcb_log( ic, "Creating new conversation: (id=%p,handle=%s)", c, handle );
-
- return c;
-}
-
-void imcb_chat_name_hint( struct groupchat *c, const char *name )
-{
- if( !c->joined )
- {
- struct im_connection *ic = c->ic;
- char stripped[MAX_NICK_LENGTH+1], *full_name;
-
- strncpy( stripped, name, MAX_NICK_LENGTH );
- stripped[MAX_NICK_LENGTH] = '\0';
- nick_strip( stripped );
- if( set_getbool( &ic->irc->set, "lcnicks" ) )
- nick_lc( stripped );
-
- full_name = g_strdup_printf( "&%s", stripped );
-
- if( stripped[0] &&
- nick_cmp( stripped, ic->irc->channel + 1 ) != 0 &&
- irc_chat_by_channel( ic->irc, full_name ) == NULL )
- {
- g_free( c->channel );
- c->channel = full_name;
- }
- else
- {
- g_free( full_name );
- }
- }
-}
-
-void imcb_chat_free( struct groupchat *c )
-{
- struct im_connection *ic = c->ic;
- struct groupchat *l;
- GList *ir;
-
- if( set_getbool( &ic->irc->set, "debug" ) )
- imcb_log( ic, "You were removed from conversation %p", c );
-
- if( c )
- {
- if( c->joined )
- {
- user_t *u, *r;
-
- r = user_find( ic->irc, ic->irc->mynick );
- irc_privmsg( ic->irc, r, "PRIVMSG", c->channel, "", "Cleaning up channel, bye!" );
-
- u = user_find( ic->irc, ic->irc->nick );
- irc_kick( ic->irc, u, c->channel, r );
- /* irc_part( ic->irc, u, c->channel ); */
- }
-
- /* Find the previous chat in the linked list. */
- for( l = ic->groupchats; l && l->next != c; l = l->next );
-
- if( l )
- l->next = c->next;
- else
- ic->groupchats = c->next;
-
- for( ir = c->in_room; ir; ir = ir->next )
- g_free( ir->data );
- g_list_free( c->in_room );
- g_free( c->channel );
- g_free( c->title );
- g_free( c->topic );
- g_free( c );
- }
-}
-
-void imcb_chat_msg( struct groupchat *c, const char *who, char *msg, uint32_t flags, time_t sent_at )
-{
- struct im_connection *ic = c->ic;
- char *wrapped;
- user_t *u;
-
- /* Gaim sends own messages through this too. IRC doesn't want this, so kill them */
- if( g_strcasecmp( who, ic->acc->user ) == 0 )
- return;
-
- u = user_findhandle( ic, who );
-
- if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
- ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
- strip_html( msg );
-
- wrapped = word_wrap( msg, 425 );
- if( c && u )
- {
- char *ts = NULL;
- if( set_getbool( &ic->irc->set, "display_timestamps" ) )
- ts = format_timestamp( ic->irc, sent_at );
- irc_privmsg( ic->irc, u, "PRIVMSG", c->channel, ts ? : "", wrapped );
- g_free( ts );
- }
- else
- {
- imcb_log( ic, "Message from/to conversation %s@%p (unknown conv/user): %s", who, c, wrapped );
- }
- g_free( wrapped );
-}
-
-void imcb_chat_log( struct groupchat *c, char *format, ... )
-{
- irc_t *irc = c->ic->irc;
- va_list params;
- char *text;
- user_t *u;
-
- va_start( params, format );
- text = g_strdup_vprintf( format, params );
- va_end( params );
-
- u = user_find( irc, irc->mynick );
-
- irc_privmsg( irc, u, "PRIVMSG", c->channel, "System message: ", text );
-
- g_free( text );
-}
-
-void imcb_chat_topic( struct groupchat *c, char *who, char *topic, time_t set_at )
-{
- struct im_connection *ic = c->ic;
- user_t *u = NULL;
-
- if( who == NULL)
- u = user_find( ic->irc, ic->irc->mynick );
- else if( g_strcasecmp( who, ic->acc->user ) == 0 )
- u = user_find( ic->irc, ic->irc->nick );
- else
- u = user_findhandle( ic, who );
-
- if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
- ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
- strip_html( topic );
-
- g_free( c->topic );
- c->topic = g_strdup( topic );
-
- if( c->joined && u )
- irc_write( ic->irc, ":%s!%s@%s TOPIC %s :%s", u->nick, u->user, u->host, c->channel, topic );
-}
-
-
-/* buddy_chat.c */
-
-void imcb_chat_add_buddy( struct groupchat *b, const char *handle )
-{
- user_t *u = user_findhandle( b->ic, handle );
- int me = 0;
-
- if( set_getbool( &b->ic->irc->set, "debug" ) )
- imcb_log( b->ic, "User %s added to conversation %p", handle, b );
-
- /* It might be yourself! */
- if( b->ic->acc->prpl->handle_cmp( handle, b->ic->acc->user ) == 0 )
- {
- u = user_find( b->ic->irc, b->ic->irc->nick );
- if( !b->joined )
- irc_join( b->ic->irc, u, b->channel );
- b->joined = me = 1;
- }
-
- /* Most protocols allow people to join, even when they're not in
- your contact list. Try to handle that here */
- if( !u )
- {
- imcb_add_buddy( b->ic, handle, NULL );
- u = user_findhandle( b->ic, handle );
- }
-
- /* Add the handle to the room userlist, if it's not 'me' */
- if( !me )
- {
- if( b->joined )
- irc_join( b->ic->irc, u, b->channel );
- b->in_room = g_list_append( b->in_room, g_strdup( handle ) );
- }
-}
-
-/* This function is one BIG hack... :-( EREWRITE */
-void imcb_chat_remove_buddy( struct groupchat *b, const char *handle, const char *reason )
-{
- user_t *u;
- int me = 0;
-
- if( set_getbool( &b->ic->irc->set, "debug" ) )
- imcb_log( b->ic, "User %s removed from conversation %p (%s)", handle, b, reason ? reason : "" );
-
- /* It might be yourself! */
- if( g_strcasecmp( handle, b->ic->acc->user ) == 0 )
- {
- if( b->joined == 0 )
- return;
-
- u = user_find( b->ic->irc, b->ic->irc->nick );
- b->joined = 0;
- me = 1;
- }
- else
- {
- u = user_findhandle( b->ic, handle );
- }
-
- if( me || ( remove_chat_buddy_silent( b, handle ) && b->joined && u ) )
- irc_part( b->ic->irc, u, b->channel );
-}
-
-static int remove_chat_buddy_silent( struct groupchat *b, const char *handle )
-{
- GList *i;
-
- /* Find the handle in the room userlist and shoot it */
- i = b->in_room;
- while( i )
- {
- if( g_strcasecmp( handle, i->data ) == 0 )
- {
- g_free( i->data );
- b->in_room = g_list_remove( b->in_room, i->data );
- return( 1 );
- }
-
- i = i->next;
- }
-
- return( 0 );
-}
-
-
-/* Misc. BitlBee stuff which shouldn't really be here */
-
-char *set_eval_away_devoice( set_t *set, char *value )
-{
- irc_t *irc = set->data;
- int st;
-
- if( !is_bool( value ) )
- return SET_INVALID;
-
- st = bool2int( value );
-
- /* Horror.... */
-
- if( st != set_getbool( &irc->set, "away_devoice" ) )
- {
- char list[80] = "";
- user_t *u = irc->users;
- int i = 0, count = 0;
- char pm;
- char v[80];
-
- if( st )
- pm = '+';
- else
- pm = '-';
-
- while( u )
- {
- if( u->ic && u->online && !u->away )
- {
- if( ( strlen( list ) + strlen( u->nick ) ) >= 79 )
- {
- for( i = 0; i < count; v[i++] = 'v' ); v[i] = 0;
- irc_write( irc, ":%s MODE %s %c%s%s",
- irc->myhost,
- irc->channel, pm, v, list );
-
- *list = 0;
- count = 0;
- }
-
- sprintf( list + strlen( list ), " %s", u->nick );
- count ++;
- }
- u = u->next;
- }
-
- /* $v = 'v' x $i */
- for( i = 0; i < count; v[i++] = 'v' ); v[i] = 0;
- irc_write( irc, ":%s MODE %s %c%s%s", irc->myhost,
- irc->channel, pm, v, list );
- }
-
- return value;
-}
-
-char *set_eval_timezone( set_t *set, char *value )
-{
- char *s;
-
- if( strcmp( value, "local" ) == 0 ||
- strcmp( value, "gmt" ) == 0 || strcmp( value, "utc" ) == 0 )
- return value;
-
- /* Otherwise: +/- at the beginning optional, then one or more numbers,
- possibly followed by a colon and more numbers. Don't bother bound-
- checking them since users are free to shoot themselves in the foot. */
- s = value;
- if( *s == '+' || *s == '-' )
- s ++;
-
- /* \d+ */
- if( !isdigit( *s ) )
- return SET_INVALID;
- while( *s && isdigit( *s ) ) s ++;
-
- /* EOS? */
- if( *s == '\0' )
- return value;
-
- /* Otherwise, colon */
- if( *s != ':' )
- return SET_INVALID;
- s ++;
-
- /* \d+ */
- if( !isdigit( *s ) )
- return SET_INVALID;
- while( *s && isdigit( *s ) ) s ++;
-
- /* EOS */
- return *s == '\0' ? value : SET_INVALID;
-}
-
-static char *format_timestamp( irc_t *irc, time_t msg_ts )
-{
- time_t now_ts = time( NULL );
- struct tm now, msg;
- char *set;
-
- /* If the timestamp is <= 0 or less than a minute ago, discard it as
- it doesn't seem to add to much useful info and/or might be noise. */
- if( msg_ts <= 0 || msg_ts > now_ts - 60 )
- return NULL;
-
- set = set_getstr( &irc->set, "timezone" );
- if( strcmp( set, "local" ) == 0 )
- {
- localtime_r( &now_ts, &now );
- localtime_r( &msg_ts, &msg );
- }
- else
- {
- int hr, min = 0, sign = 60;
-
- if( set[0] == '-' )
- {
- sign *= -1;
- set ++;
- }
- else if( set[0] == '+' )
- {
- set ++;
- }
-
- if( sscanf( set, "%d:%d", &hr, &min ) >= 1 )
- {
- msg_ts += sign * ( hr * 60 + min );
- now_ts += sign * ( hr * 60 + min );
- }
-
- gmtime_r( &now_ts, &now );
- gmtime_r( &msg_ts, &msg );
- }
-
- if( msg.tm_year == now.tm_year && msg.tm_yday == now.tm_yday )
- return g_strdup_printf( "\x02[\x02\x02\x02%02d:%02d:%02d\x02]\x02 ",
- msg.tm_hour, msg.tm_min, msg.tm_sec );
- else
- return g_strdup_printf( "\x02[\x02\x02\x02%04d-%02d-%02d "
- "%02d:%02d:%02d\x02]\x02 ",
- msg.tm_year + 1900, msg.tm_mon + 1, msg.tm_mday,
- msg.tm_hour, msg.tm_min, msg.tm_sec );
+ return bee_user_by_handle( ic->bee, ic, handle );
}
/* The plan is to not allow straight calls to prpl functions anymore, but do
them all from some wrappers. We'll start to define some down here: */
-int imc_buddy_msg( struct im_connection *ic, char *handle, char *msg, int flags )
-{
- char *buf = NULL;
- int st;
-
- if( ( ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )
- {
- buf = escape_html( msg );
- msg = buf;
- }
-
- st = ic->acc->prpl->buddy_msg( ic, handle, msg, flags );
- g_free( buf );
-
- return st;
-}
-
int imc_chat_msg( struct groupchat *c, char *msg, int flags )
{
char *buf = NULL;
@@ -1310,7 +540,7 @@ int imc_away_send_update( struct im_connection *ic )
return 0;
away = set_getstr( &ic->acc->set, "away" ) ?
- : set_getstr( &ic->irc->set, "away" );
+ : set_getstr( &ic->bee->set, "away" );
if( away && *away )
{
GList *m = ic->acc->prpl->away_states( ic );
@@ -1321,7 +551,7 @@ int imc_away_send_update( struct im_connection *ic )
{
away = NULL;
msg = set_getstr( &ic->acc->set, "status" ) ?
- : set_getstr( &ic->irc->set, "status" );
+ : set_getstr( &ic->bee->set, "status" );
}
ic->acc->prpl->set_away( ic, away, msg );
diff --git a/protocols/nogaim.h b/protocols/nogaim.h
index 21b461f8..5ce62742 100644
--- a/protocols/nogaim.h
+++ b/protocols/nogaim.h
@@ -1,7 +1,7 @@
/********************************************************************\
* BitlBee -- An IRC to other IM-networks gateway *
* *
- * Copyright 2002-2004 Wilmer van der Gaast and others *
+ * Copyright 2002-2010 Wilmer van der Gaast and others *
\********************************************************************/
/*
@@ -86,9 +86,9 @@ struct im_connection
int evil;
/* BitlBee */
- irc_t *irc;
+ bee_t *bee;
- struct groupchat *groupchats;
+ GSList *groupchats;
};
struct groupchat {
@@ -99,10 +99,9 @@ struct groupchat {
* "nick list". This is how you can check who is in the group chat
* already, for example to avoid adding somebody two times. */
GList *in_room;
- GList *ignored;
+ //GList *ignored;
- struct groupchat *next;
- char *channel;
+ //struct groupchat *next;
/* The title variable contains the ID you gave when you created the
* chat using imcb_chat_new(). */
char *title;
@@ -113,6 +112,7 @@ struct groupchat {
/* This is for you, you can add your own structure here to extend this
* structure for your protocol's needs. */
void *data;
+ void *ui_data;
};
struct buddy {
@@ -286,16 +286,8 @@ G_MODULE_EXPORT struct buddy *imcb_find_buddy( struct im_connection *ic, char *h
G_MODULE_EXPORT void imcb_rename_buddy( struct im_connection *ic, const char *handle, const char *realname );
G_MODULE_EXPORT void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick );
-/* Buddy activity */
-/* To manipulate the status of a handle.
- * - flags can be |='d with OPT_* constants. You will need at least:
- * OPT_LOGGED_IN and OPT_AWAY.
- * - 'state' and 'message' can be NULL */
-G_MODULE_EXPORT void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message );
-/* Not implemented yet! */ G_MODULE_EXPORT void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle );
-/* Call when a handle says something. 'flags' and 'sent_at may be just 0. */
-G_MODULE_EXPORT void imcb_buddy_msg( struct im_connection *ic, const char *handle, char *msg, uint32_t flags, time_t sent_at );
G_MODULE_EXPORT void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags );
+G_MODULE_EXPORT struct bee_user *imcb_buddy_by_handle( struct im_connection *ic, const char *handle );
G_MODULE_EXPORT void imcb_clean_handle( struct im_connection *ic, char *handle );
/* Groupchats */
@@ -321,7 +313,6 @@ G_MODULE_EXPORT void imcb_chat_free( struct groupchat *c );
/* Actions, or whatever. */
int imc_away_send_update( struct im_connection *ic );
-int imc_buddy_msg( struct im_connection *ic, char *handle, char *msg, int flags );
int imc_chat_msg( struct groupchat *c, char *msg, int flags );
void imc_add_allow( struct im_connection *ic, char *handle );
diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c
index 7086657a..acae6433 100644
--- a/protocols/oscar/oscar.c
+++ b/protocols/oscar/oscar.c
@@ -253,8 +253,6 @@ static char *normalize(const char *s)
g_return_val_if_fail((s != NULL), NULL);
u = t = g_strdup(s);
-
- strcpy(t, s);
g_strdown(t);
while (*t && (x < BUF_LEN - 1)) {
@@ -651,6 +649,7 @@ static int gaim_parse_logout(aim_session_t *sess, aim_frame_t *fr, ...) {
static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...) {
struct im_connection *ic = sess->aux_data;
struct chat_connection *chatcon;
+ struct groupchat *c = NULL;
static int id = 1;
aim_conn_addhandler(sess, fr->conn, 0x000e, 0x0001, gaim_parse_genericerr, 0);
@@ -663,7 +662,12 @@ static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...) {
chatcon = find_oscar_chat_by_conn(ic, fr->conn);
chatcon->id = id;
- chatcon->cnv = imcb_chat_new(ic, chatcon->show);
+
+ c = bee_chat_by_title(ic->bee, ic, chatcon->show);
+ if (c && !c->data)
+ chatcon->cnv = c;
+ else
+ chatcon->cnv = imcb_chat_new(ic, chatcon->show);
chatcon->cnv->data = chatcon;
return 1;
@@ -933,7 +937,7 @@ static int gaim_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...) {
tmp = normalize(info->sn);
imcb_buddy_status(ic, tmp, flags, state_string, NULL);
- /* imcb_buddy_times(ic, tmp, signon, time_idle); */
+ imcb_buddy_times(ic, tmp, signon, time_idle);
return 1;
@@ -1059,8 +1063,7 @@ static void gaim_icq_authgrant(void *data_) {
message = 0;
aim_ssi_auth_reply(od->sess, od->conn, uin, 1, "");
// aim_send_im_ch4(od->sess, uin, AIM_ICQMSG_AUTHGRANTED, &message);
- if(imcb_find_buddy(data->ic, uin) == NULL)
- imcb_ask_add(data->ic, uin, NULL);
+ imcb_ask_add(data->ic, uin, NULL);
g_free(uin);
g_free(data);
@@ -1821,11 +1824,13 @@ static void oscar_get_info(struct im_connection *g, char *name) {
static void oscar_get_away(struct im_connection *g, char *who) {
struct oscar_data *odata = (struct oscar_data *)g->proto_data;
if (odata->icq) {
+ /** FIXME(wilmer): Hmm, lost the ability to get away msgs here, do we care to get that back?
struct buddy *budlight = imcb_find_buddy(g, who);
if (budlight)
if ((budlight->uc & 0xff80) >> 7)
if (budlight->caps & AIM_CAPS_ICQSERVERRELAY)
aim_send_im_ch2_geticqmessage(odata->sess, who, (budlight->uc & 0xff80) >> 7);
+ */
} else
aim_getinfo(odata->sess, odata->conn, who, AIM_GETINFO_AWAYMESSAGE);
}
@@ -1952,7 +1957,7 @@ static int gaim_ssi_parserights(aim_session_t *sess, aim_frame_t *fr, ...) {
static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) {
struct im_connection *ic = sess->aux_data;
- struct aim_ssi_item *curitem;
+ struct aim_ssi_item *curitem, *curgroup;
int tmp;
char *nrm;
@@ -1963,13 +1968,13 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) {
switch (curitem->type) {
case 0x0000: /* Buddy */
- if ((curitem->name) && (!imcb_find_buddy(ic, nrm))) {
+ if ((curitem->name) && (!imcb_buddy_by_handle(ic, nrm))) {
char *realname = NULL;
if (curitem->data && aim_gettlv(curitem->data, 0x0131, 1))
realname = aim_gettlv_str(curitem->data, 0x0131, 1);
-
- imcb_add_buddy(ic, nrm, NULL);
+
+ imcb_add_buddy(ic, nrm, curgroup->gid == curitem->gid ? curgroup->name : NULL);
if (realname) {
imcb_buddy_nick_hint(ic, nrm, realname);
@@ -1979,6 +1984,10 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) {
}
break;
+ case 0x0001: /* Group */
+ curgroup = curitem;
+ break;
+
case 0x0002: /* Permit buddy */
if (curitem->name) {
GSList *list;
@@ -2519,12 +2528,13 @@ struct groupchat *oscar_chat_with(struct im_connection * ic, char *who)
struct groupchat *ret;
static int chat_id = 0;
char * chatname;
+ struct groupchat *c;
chatname = g_strdup_printf("%s%s_%d", isdigit(*ic->acc->user) ? "icq_" : "",
ic->acc->user, chat_id++);
-
+
+ c = imcb_chat_new(ic, chatname);
ret = oscar_chat_join(ic, chatname, NULL, NULL);
-
aim_chat_invite(od->sess, od->conn, who, "", 4, chatname, 0x0);
g_free(chatname);
diff --git a/protocols/purple/ft.c b/protocols/purple/ft.c
index e3a89524..c4efc657 100644
--- a/protocols/purple/ft.c
+++ b/protocols/purple/ft.c
@@ -74,6 +74,7 @@ static void prplcb_xfer_new( PurpleXfer *xfer )
px->xfer = xfer;
px->fn = mktemp( g_strdup( "/tmp/bitlbee-purple-ft.XXXXXX" ) );
px->fd = -1;
+ px->ic = purple_ic_by_pa( xfer->account );
purple_xfer_set_local_filename( xfer, px->fn );
@@ -142,14 +143,14 @@ gboolean try_write_to_ui( gpointer data, gint fd, b_input_condition cond )
else
{
purple_xfer_cancel_local( px->xfer );
- imcb_file_canceled( ft, "Read error" );
+ imcb_file_canceled( px->ic, ft, "Read error" );
}
}
if( lseek( px->fd, 0, SEEK_CUR ) == px->xfer->size )
{
/*purple_xfer_end( px->xfer );*/
- imcb_file_finished( ft );
+ imcb_file_finished( px->ic, ft );
}
return FALSE;
@@ -229,7 +230,7 @@ static void prplcb_xfer_cancel_remote( PurpleXfer *xfer )
struct prpl_xfer_data *px = xfer->ui_data;
if( px->ft )
- imcb_file_canceled( px->ft, "Canceled by remote end" );
+ imcb_file_canceled( px->ic, px->ft, "Canceled by remote end" );
else
/* px->ft == NULL for sends, because of the two stages. :-/ */
imcb_error( px->ic, "File transfer cancelled by remote end" );
@@ -300,11 +301,12 @@ static void purple_transfer_forward( struct file_transfer *ft )
static gboolean purple_transfer_request_cb( gpointer data, gint fd, b_input_condition cond )
{
file_transfer_t *ft = data;
+ struct prpl_xfer_data *px = ft->data;
if( ft->write == NULL )
{
ft->write = prpl_xfer_write;
- imcb_file_recv_start( ft );
+ imcb_file_recv_start( px->ic, ft );
}
ft->write_request( ft );
@@ -318,7 +320,7 @@ static gboolean prpl_xfer_write( struct file_transfer *ft, char *buffer, unsigne
if( write( px->fd, buffer, len ) != len )
{
- imcb_file_canceled( ft, "Error while writing temporary file" );
+ imcb_file_canceled( px->ic, ft, "Error while writing temporary file" );
return FALSE;
}
@@ -328,7 +330,7 @@ static gboolean prpl_xfer_write( struct file_transfer *ft, char *buffer, unsigne
px->fd = -1;
purple_transfer_forward( ft );
- imcb_file_finished( ft );
+ imcb_file_finished( px->ic, ft );
px->ft = NULL;
}
else
diff --git a/protocols/purple/purple.c b/protocols/purple/purple.c
index 98cd2241..2804fdf3 100644
--- a/protocols/purple/purple.c
+++ b/protocols/purple/purple.c
@@ -34,7 +34,7 @@ GSList *purple_connections;
/* This makes me VERY sad... :-( But some libpurple callbacks come in without
any context so this is the only way to get that. Don't want to support
libpurple in daemon mode anyway. */
-static irc_t *local_irc;
+static bee_t *local_bee;
static char *set_eval_display_name( set_t *set, char *value );
@@ -156,8 +156,11 @@ static void purple_init( account_t *acc )
break;
default:
+ /** No way to talk to the user right now, invent one when
+ this becomes important.
irc_usermsg( acc->irc, "Setting with unknown type: %s (%d) Expect stuff to break..\n",
name, purple_account_option_get_type( o ) );
+ */
name = NULL;
}
@@ -250,13 +253,14 @@ static void purple_login( account_t *acc )
struct im_connection *ic = imcb_new( acc );
PurpleAccount *pa;
- if( local_irc != NULL && local_irc != acc->irc )
+ if( local_bee != NULL && local_bee != acc->bee )
{
- irc_usermsg( acc->irc, "Daemon mode detected. Do *not* try to use libpurple in daemon mode! "
- "Please use inetd or ForkDaemon mode instead." );
+ imcb_error( ic, "Daemon mode detected. Do *not* try to use libpurple in daemon mode! "
+ "Please use inetd or ForkDaemon mode instead." );
+ imc_logout( ic, FALSE );
return;
}
- local_irc = acc->irc;
+ local_bee = acc->bee;
/* For now this is needed in the _connected() handlers if using
GLib event handling, to make sure we're not handling events
@@ -682,6 +686,10 @@ static void prplcb_blist_update( PurpleBuddyList *list, PurpleBlistNode *node )
imcb_buddy_status( ic, bud->name, flags, purple_status_get_name( as ),
purple_status_get_attr_string( as, "message" ) );
+
+ imcb_buddy_times( ic, bud->name,
+ purple_presence_get_login_time( bud->presence ),
+ purple_presence_get_idle_time( bud->presence ) );
}
}
@@ -865,8 +873,9 @@ static void *prplcb_request_action( const char *title, const char *primary, cons
pqad->user_data = user_data;
+ /* TODO: IRC stuff here :-( */
q = g_strdup_printf( "Request: %s\n\n%s\n\n%s", title, primary, secondary );
- pqad->bee_data = query_add( local_irc, purple_ic_by_pa( account ), q,
+ pqad->bee_data = query_add( local_bee->ui_data, purple_ic_by_pa( account ), q,
prplcb_request_action_yes, prplcb_request_action_no, pqad );
g_free( q );
diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c
index 585bdd43..9b67442e 100644
--- a/protocols/twitter/twitter_lib.c
+++ b/protocols/twitter/twitter_lib.c
@@ -102,7 +102,7 @@ static void twitter_add_buddy(struct im_connection *ic, char *name, const char *
struct twitter_data *td = ic->proto_data;
// Check if the buddy is allready in the buddy list.
- if (!imcb_find_buddy( ic, name ))
+ if (!bee_user_by_handle( ic->bee, ic, name ))
{
char *mode = set_getstr(&ic->acc->set, "mode");
diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c
index c3ec7bff..bf577496 100644
--- a/protocols/yahoo/yahoo.c
+++ b/protocols/yahoo/yahoo.c
@@ -157,7 +157,7 @@ static void byahoo_logout( struct im_connection *ic )
GSList *l;
while( ic->groupchats )
- imcb_chat_free( ic->groupchats );
+ imcb_chat_free( ic->groupchats->data );
for( l = yd->buddygroups; l; l = l->next )
{
@@ -612,10 +612,8 @@ void ext_yahoo_status_changed( int id, const char *who, int stat, const char *ms
imcb_buddy_status( ic, who, flags, state_string, msg );
- /* Not implemented yet...
if( stat == YAHOO_STATUS_IDLE )
- imcb_buddy_times( ic, who, 0, away );
- */
+ imcb_buddy_times( ic, who, 0, idle );
}
void ext_yahoo_got_im( int id, const char *me, const char *who, const char *msg, long tm, int stat, int utf8 )
@@ -795,10 +793,14 @@ static void byahoo_accept_conf( void *data )
{
struct byahoo_conf_invitation *inv = data;
struct groupchat *b;
+ GSList *l;
- for( b = inv->ic->groupchats; b; b = b->next )
+ for( l = inv->ic->groupchats; l; l = l->next )
+ {
+ b = l->data;
if( b == inv->c )
break;
+ }
if( b != NULL )
{
@@ -864,9 +866,7 @@ void ext_yahoo_conf_userdecline( int id, const char *ignored, const char *who, c
void ext_yahoo_conf_userjoin( int id, const char *ignored, const char *who, const char *room )
{
struct im_connection *ic = byahoo_get_ic_by_id( id );
- struct groupchat *c;
-
- for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next );
+ struct groupchat *c = bee_chat_by_title( ic->bee, ic, room );
if( c )
imcb_chat_add_buddy( c, (char*) who );
@@ -876,9 +876,7 @@ void ext_yahoo_conf_userleave( int id, const char *ignored, const char *who, con
{
struct im_connection *ic = byahoo_get_ic_by_id( id );
- struct groupchat *c;
-
- for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next );
+ struct groupchat *c = bee_chat_by_title( ic->bee, ic, room );
if( c )
imcb_chat_remove_buddy( c, (char*) who, "" );
@@ -888,9 +886,7 @@ void ext_yahoo_conf_message( int id, const char *ignored, const char *who, const
{
struct im_connection *ic = byahoo_get_ic_by_id( id );
char *m = byahoo_strip( msg );
- struct groupchat *c;
-
- for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next );
+ struct groupchat *c = bee_chat_by_title( ic->bee, ic, room );
if( c )
imcb_chat_msg( c, (char*) who, (char*) m, 0, 0 );