source: protocols/purple/purple.c @ 6967d01

Last change on this file since 6967d01 was 6967d01, checked in by Wilmer van der Gaast <wilmer@…>, at 2009-10-14T21:36:09Z

I think daemon mode and libpurple won't go together very well for now since
libpurple seems to keep track of a merged contact list. For now people
shouldn't be trying this combination.

  • Property mode set to 100644
File size: 13.2 KB
RevLine 
[796da03]1/***************************************************************************\
2*                                                                           *
3*  BitlBee - An IRC to IM gateway                                           *
4*  libpurple module - Main file                                             *
5*                                                                           *
6*  Copyright 2009 Wilmer van der Gaast <wilmer@gaast.net>                   *
7*                                                                           *
8*  This program is free software; you can redistribute it and/or modify     *
9*  it under the terms of the GNU General Public License as published by     *
10*  the Free Software Foundation; either version 2 of the License, or        *
11*  (at your option) any later version.                                      *
12*                                                                           *
13*  This program is distributed in the hope that it will be useful,          *
14*  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
15*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
16*  GNU General Public License for more details.                             *
17*                                                                           *
18*  You should have received a copy of the GNU General Public License along  *
19*  with this program; if not, write to the Free Software Foundation, Inc.,  *
20*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.              *
21*                                                                           *
22\***************************************************************************/
23
24#include <glib.h>
25#include <purple.h>
26
27#include "bitlbee.h"
28
29GSList *purple_connections;
30
[7da726b]31static struct im_connection *purple_ic_by_pa( PurpleAccount *pa )
[860ba6a]32{
33        GSList *i;
34       
35        for( i = purple_connections; i; i = i->next )
36                if( ((struct im_connection *)i->data)->proto_data == pa )
37                        return i->data;
38       
39        return NULL;
40}
41
[7da726b]42static struct im_connection *purple_ic_by_gc( PurpleConnection *gc )
43{
44        return purple_ic_by_pa( purple_connection_get_account( gc ) );
45}
46
[796da03]47static void purple_init( account_t *acc )
48{
[0f7ee7e5]49        PurplePlugin *prpl = purple_plugins_find_with_id( acc->prpl->name );
50        PurplePluginProtocolInfo *pi = prpl->info->extra_info;
51        GList *i;
[0cbef26]52       
[0f7ee7e5]53        for( i = pi->protocol_options; i; i = i->next )
54        {
55                PurpleAccountOption *o = i->data;
56                const char *name;
57                char *def = NULL;
58                set_eval eval = NULL;
59                set_t *s;
60               
61                name = purple_account_option_get_setting( o );
62               
63                switch( purple_account_option_get_type( o ) )
64                {
65                case PURPLE_PREF_STRING:
66                        def = g_strdup( purple_account_option_get_default_string( o ) );
67                        break;
68               
69                case PURPLE_PREF_INT:
70                        def = g_strdup_printf( "%d", purple_account_option_get_default_int( o ) );
71                        eval = set_eval_int;
72                        break;
73               
74                case PURPLE_PREF_BOOLEAN:
75                        if( purple_account_option_get_default_bool( o ) )
76                                def = g_strdup( "true" );
77                        else
78                                def = g_strdup( "false" );
79                        eval = set_eval_bool;
80                        break;
81               
82                default:
83                        fprintf( stderr, "Setting with unknown type: %s (%d)\n", name, purple_account_option_get_type( o ) );
84                }
85               
86                if( def != NULL )
87                {
88                        s = set_add( &acc->set, name, def, eval, acc );
89                        s->flags |= ACC_SET_OFFLINE_ONLY;
90                        g_free( def );
91                }
92        }
[796da03]93}
94
[b74b287]95static void purple_sync_settings( account_t *acc, PurpleAccount *pa )
96{
97        PurplePlugin *prpl = purple_plugins_find_with_id( pa->protocol_id );
98        PurplePluginProtocolInfo *pi = prpl->info->extra_info;
99        GList *i;
100       
101        for( i = pi->protocol_options; i; i = i->next )
102        {
103                PurpleAccountOption *o = i->data;
104                const char *name;
105                set_t *s;
106               
107                name = purple_account_option_get_setting( o );
108                s = set_find( &acc->set, name );
109                if( s->value == NULL )
110                        continue;
111               
112                switch( purple_account_option_get_type( o ) )
113                {
114                case PURPLE_PREF_STRING:
115                        purple_account_set_string( pa, name, set_getstr( &acc->set, name ) );
116                        break;
117               
118                case PURPLE_PREF_INT:
119                        purple_account_set_int( pa, name, set_getint( &acc->set, name ) );
120                        break;
121               
122                case PURPLE_PREF_BOOLEAN:
123                        purple_account_set_bool( pa, name, set_getbool( &acc->set, name ) );
124                        break;
125               
126                default:
127                        break;
128                }
129        }
130}
131
[796da03]132static void purple_login( account_t *acc )
133{
134        struct im_connection *ic = imcb_new( acc );
[6967d01]135        static void *irc_check = NULL;
[860ba6a]136        PurpleAccount *pa;
[796da03]137       
[6967d01]138        if( irc_check != NULL && irc_check != acc->irc )
139        {
140                irc_usermsg( acc->irc, "Daemon mode detected. Do *not* try to use libpurple in daemon mode! Please use inetd or ForkDaemon mode instead." );
141                return;
142        }
143        irc_check = acc->irc;
144       
[796da03]145        /* For now this is needed in the _connected() handlers if using
146           GLib event handling, to make sure we're not handling events
147           on dead connections. */
148        purple_connections = g_slist_prepend( purple_connections, ic );
149       
[b74b287]150        ic->proto_data = pa = purple_account_new( acc->user, acc->prpl->name );
[860ba6a]151        purple_account_set_password( pa, acc->pass );
[b74b287]152        purple_sync_settings( acc, pa );
[860ba6a]153       
154        purple_account_set_enabled( pa, "BitlBee", TRUE );
[796da03]155}
156
157static void purple_logout( struct im_connection *ic )
158{
[db4cd40]159        PurpleAccount *pa = ic->proto_data;
160       
161        purple_account_set_enabled( pa, "BitlBee", FALSE );
[796da03]162        purple_connections = g_slist_remove( purple_connections, ic );
[b74b287]163        purple_accounts_remove( pa );
[796da03]164}
165
166static int purple_buddy_msg( struct im_connection *ic, char *who, char *message, int flags )
167{
[389f7be]168        PurpleConversation *conv;
169       
170        if( ( conv = purple_find_conversation_with_account( PURPLE_CONV_TYPE_IM,
171                                                            who, ic->proto_data ) ) == NULL )
172        {
173                conv = purple_conversation_new( PURPLE_CONV_TYPE_IM,
174                                                ic->proto_data, who );
175        }
176       
177        purple_conv_im_send( purple_conversation_get_im_data( conv ), message );
[0cbef26]178       
179        return 1;
[796da03]180}
181
182static GList *purple_away_states( struct im_connection *ic )
183{
[ec5e57d]184        PurpleAccount *pa = ic->proto_data;
185        GList *st, *ret = NULL;
186       
187        for( st = purple_account_get_status_types( pa ); st; st = st->next )
188                ret = g_list_append( ret, (void*) purple_status_type_get_name( st->data ) );
189       
190        return ret;
[796da03]191}
192
193static void purple_set_away( struct im_connection *ic, char *state_txt, char *message )
194{
[ec5e57d]195        PurpleAccount *pa = ic->proto_data;
196        GList *status_types = purple_account_get_status_types( pa ), *st;
197        PurpleStatusType *pst = NULL;
198       
199        for( st = status_types; st; st = st->next )
200        {
201                pst = st->data;
202               
203                if( g_strcasecmp( state_txt, purple_status_type_get_name( pst ) ) == 0 )
204                        break;
205        }
206       
207        purple_account_set_status( pa, st ? purple_status_type_get_id( pst ) : "away",
208                                   TRUE, "message", message, NULL );
[796da03]209}
210
211static void purple_add_buddy( struct im_connection *ic, char *who, char *group )
212{
213}
214
215static void purple_remove_buddy( struct im_connection *ic, char *who, char *group )
216{
217}
218
219static void purple_keepalive( struct im_connection *ic )
220{
221}
222
223static int purple_send_typing( struct im_connection *ic, char *who, int typing )
224{
[0cbef26]225        return 1;
[796da03]226}
227
[860ba6a]228static void purple_ui_init();
229
230static PurpleCoreUiOps bee_core_uiops = 
231{
232        NULL,
233        NULL,
234        purple_ui_init,
235        NULL,
236};
237
238static void prplcb_conn_progress( PurpleConnection *gc, const char *text, size_t step, size_t step_count )
239{
[0cbef26]240        struct im_connection *ic = purple_ic_by_gc( gc );
241       
242        imcb_log( ic, "%s", text );
[860ba6a]243}
244
245static void prplcb_conn_connected( PurpleConnection *gc )
246{
[d250b2a]247        struct im_connection *ic = purple_ic_by_gc( gc );
248       
249        imcb_connected( ic );
250       
251        if( gc->flags & PURPLE_CONNECTION_HTML )
252                ic->flags |= OPT_DOES_HTML;
[860ba6a]253}
254
255static void prplcb_conn_disconnected( PurpleConnection *gc )
256{
[0cbef26]257        struct im_connection *ic = purple_ic_by_gc( gc );
258       
259        if( ic != NULL )
[b74b287]260        {
[0cbef26]261                imc_logout( ic, TRUE );
[b74b287]262        }
[860ba6a]263}
264
265static void prplcb_conn_notice( PurpleConnection *gc, const char *text )
266{
[0cbef26]267        struct im_connection *ic = purple_ic_by_gc( gc );
268       
269        if( ic != NULL )
270                imcb_log( ic, "%s", text );
[860ba6a]271}
272
273static void prplcb_conn_report_disconnect_reason( PurpleConnection *gc, PurpleConnectionError reason, const char *text )
274{
[0cbef26]275        struct im_connection *ic = purple_ic_by_gc( gc );
276       
[860ba6a]277        /* PURPLE_CONNECTION_ERROR_NAME_IN_USE means concurrent login,
278           should probably handle that. */
[0cbef26]279        if( ic != NULL )
280                imcb_error( ic, "%s", text );
[860ba6a]281}
282
283static PurpleConnectionUiOps bee_conn_uiops =
284{
285        prplcb_conn_progress,
286        prplcb_conn_connected,
287        prplcb_conn_disconnected,
288        prplcb_conn_notice,
289        NULL,
290        NULL,
291        NULL,
292        prplcb_conn_report_disconnect_reason,
293};
294
[7da726b]295static void prplcb_blist_new( PurpleBlistNode *node )
296{
297        PurpleBuddy *bud = (PurpleBuddy*) node;
298       
[db4cd40]299        if( node->type == PURPLE_BLIST_BUDDY_NODE )
[7da726b]300        {
[db4cd40]301                struct im_connection *ic = purple_ic_by_pa( bud->account );
302               
303                if( ic == NULL )
304                        return;
305               
[7da726b]306                imcb_add_buddy( ic, bud->name, NULL );
307                if( bud->server_alias )
[4524f66]308                {
309                        imcb_rename_buddy( ic, bud->name, bud->server_alias );
[7da726b]310                        imcb_buddy_nick_hint( ic, bud->name, bud->server_alias );
[4524f66]311                }
[7da726b]312        }
313}
314
315static void prplcb_blist_update( PurpleBuddyList *list, PurpleBlistNode *node )
316{
317        PurpleBuddy *bud = (PurpleBuddy*) node;
318       
[db4cd40]319        if( node->type == PURPLE_BLIST_BUDDY_NODE )
[7da726b]320        {
[db4cd40]321                struct im_connection *ic = purple_ic_by_pa( bud->account );
[4f103ea]322                PurpleStatus *as;
323                int flags = 0;
324               
[db4cd40]325                if( ic == NULL )
326                        return;
327               
[4524f66]328                if( bud->server_alias )
329                        imcb_rename_buddy( ic, bud->name, bud->server_alias );
330               
[4f103ea]331                flags |= purple_presence_is_online( bud->presence ) ? OPT_LOGGED_IN : 0;
332                flags |= purple_presence_is_available( bud->presence ) ? 0 : OPT_AWAY;
333               
334                as = purple_presence_get_active_status( bud->presence );
335               
336                imcb_buddy_status( ic, bud->name, flags, purple_status_get_name( as ),
337                                   purple_status_get_attr_string( as, "message" ) );
[7da726b]338        }
339}
340
341static void prplcb_blist_remove( PurpleBuddyList *list, PurpleBlistNode *node )
342{
343        PurpleBuddy *bud = (PurpleBuddy*) node;
344       
[db4cd40]345        if( node->type == PURPLE_BLIST_BUDDY_NODE )
[0cbef26]346        {
[db4cd40]347                struct im_connection *ic = purple_ic_by_pa( bud->account );
348               
349                if( ic == NULL )
350                        return;
351               
[0cbef26]352                imcb_remove_buddy( ic, bud->name, NULL );
353        }
[7da726b]354}
355
356static PurpleBlistUiOps bee_blist_uiops =
357{
358        NULL,
359        prplcb_blist_new,
360        NULL,
361        prplcb_blist_update,
362        prplcb_blist_remove,
363};
364
[d250b2a]365static void prplcb_conv_im( PurpleConversation *conv, const char *who, const char *message, PurpleMessageFlags flags, time_t mtime )
366{
367        struct im_connection *ic = purple_ic_by_pa( conv->account );
368       
[389f7be]369        /* ..._SEND means it's an outgoing message, no need to echo those. */
370        if( !( flags & PURPLE_MESSAGE_SEND ) )
371                imcb_buddy_msg( ic, (char*) who, (char*) message, 0, mtime );
[d250b2a]372}
373
[860ba6a]374static PurpleConversationUiOps bee_conv_uiops = 
375{
376        NULL,                      /* create_conversation  */
377        NULL,                      /* destroy_conversation */
378        NULL,                      /* write_chat           */
[d250b2a]379        prplcb_conv_im,            /* write_im             */
[e046390]380        NULL,                      /* write_conv           */
[860ba6a]381        NULL,                      /* chat_add_users       */
382        NULL,                      /* chat_rename_user     */
383        NULL,                      /* chat_remove_users    */
384        NULL,                      /* chat_update_user     */
385        NULL,                      /* present              */
386        NULL,                      /* has_focus            */
387        NULL,                      /* custom_smiley_add    */
388        NULL,                      /* custom_smiley_write  */
389        NULL,                      /* custom_smiley_close  */
390        NULL,                      /* send_confirm         */
391};
392
[0cbef26]393static void prplcb_debug_print( PurpleDebugLevel level, const char *category, const char *arg_s )
394{
[6967d01]395        fprintf( stderr, "DEBUG %s: %s", category, arg_s );
[0cbef26]396}
397
398static PurpleDebugUiOps bee_debug_uiops =
399{
400        prplcb_debug_print,
401};
402
[4164e62]403static guint prplcb_ev_timeout_add( guint interval, GSourceFunc func, gpointer udata )
404{
405        return b_timeout_add( interval, (b_event_handler) func, udata );
406}
407
408static guint prplcb_ev_input_add( int fd, PurpleInputCondition cond, PurpleInputFunction func, gpointer udata )
409{
410        return b_input_add( fd, cond | B_EV_FLAG_FORCE_REPEAT, (b_event_handler) func, udata );
411}
412
413static gboolean prplcb_ev_remove( guint id )
414{
415        b_event_remove( (gint) id );
416        return TRUE;
417}
418
419static PurpleEventLoopUiOps glib_eventloops = 
420{
421        prplcb_ev_timeout_add,
422        prplcb_ev_remove,
423        prplcb_ev_input_add,
424        prplcb_ev_remove,
425};
426
[860ba6a]427static void purple_ui_init()
428{
[7da726b]429        purple_blist_set_ui_ops( &bee_blist_uiops );
[860ba6a]430        purple_connections_set_ui_ops( &bee_conn_uiops );
431        purple_conversations_set_ui_ops( &bee_conv_uiops );
[0cbef26]432        //purple_debug_set_ui_ops( &bee_debug_uiops );
[860ba6a]433}
434
[796da03]435void purple_initmodule()
436{
437        GList *prots;
438       
[e046390]439        if( B_EV_IO_READ != PURPLE_INPUT_READ ||
440            B_EV_IO_WRITE != PURPLE_INPUT_WRITE )
441        {
442                /* FIXME FIXME FIXME FIXME FIXME :-) */
443                exit( 1 );
444        }
445       
[796da03]446        purple_util_set_user_dir("/tmp");
447        purple_debug_set_enabled(FALSE);
448        purple_core_set_ui_ops(&bee_core_uiops);
449        purple_eventloop_set_ui_ops(&glib_eventloops);
450        if( !purple_core_init( "BitlBee") )
451        {
452                /* Initializing the core failed. Terminate. */
453                fprintf( stderr, "libpurple initialization failed.\n" );
454                abort();
455        }
456       
457        /* This seems like stateful shit we don't want... */
458        purple_set_blist(purple_blist_new());
459        purple_blist_load();
460       
461        /* Meh? */
462        purple_prefs_load();
463       
464        for( prots = purple_plugins_get_protocols(); prots; prots = prots->next )
465        {
466                struct prpl *ret = g_new0( struct prpl, 1 );
467                PurplePlugin *prot = prots->data;
468               
469                ret->name = prot->info->id;
470                ret->login = purple_login;
471                ret->init = purple_init;
472                ret->logout = purple_logout;
473                ret->buddy_msg = purple_buddy_msg;
474                ret->away_states = purple_away_states;
475                ret->set_away = purple_set_away;
476                ret->add_buddy = purple_add_buddy;
477                ret->remove_buddy = purple_remove_buddy;
478                ret->keepalive = purple_keepalive;
479                ret->send_typing = purple_send_typing;
480                ret->handle_cmp = g_strcasecmp;
481               
482                register_protocol( ret );
483        }
484}
Note: See TracBrowser for help on using the repository browser.