source: protocols/purple/purple.c @ c5c18c1

Last change on this file since c5c18c1 was c5c18c1, checked in by Wilmer van der Gaast <wilmer@…>, at 2009-10-10T23:57:26Z

Hacked up a B_EV_FLAG_FORCE_REPEAT event handler flag to make libpurple
happy.

  • Property mode set to 100644
File size: 10.7 KB
Line 
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
31#undef g_io_add_watch
32#undef g_io_add_watch_full
33#undef g_timeout_add
34#undef g_source_remove
35
36/**
37 * The following eventloop functions are used in both pidgin and purple-text. If your
38 * application uses glib mainloop, you can safely use this verbatim.
39 */
40#define PURPLE_GLIB_READ_COND  (G_IO_IN | G_IO_HUP | G_IO_ERR)
41#define PURPLE_GLIB_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL)
42
43typedef struct _PurpleGLibIOClosure {
44        PurpleInputFunction function;
45        guint result;
46        gpointer data;
47} PurpleGLibIOClosure;
48
49static struct im_connection *purple_ic_by_pa( PurpleAccount *pa )
50{
51        GSList *i;
52       
53        for( i = purple_connections; i; i = i->next )
54                if( ((struct im_connection *)i->data)->proto_data == pa )
55                        return i->data;
56       
57        return NULL;
58}
59
60static struct im_connection *purple_ic_by_gc( PurpleConnection *gc )
61{
62        return purple_ic_by_pa( purple_connection_get_account( gc ) );
63}
64
65static guint prplcb_ev_timeout_add( guint interval, GSourceFunc func, gpointer udata )
66{
67        return b_timeout_add( interval, (b_event_handler) func, udata );
68}
69
70static guint prplcb_ev_input_add( int fd, PurpleInputCondition cond, PurpleInputFunction func, gpointer udata )
71{
72        return (guint) b_input_add( fd, cond | B_EV_FLAG_FORCE_REPEAT, (b_event_handler) func, udata );
73}
74
75static PurpleEventLoopUiOps glib_eventloops = 
76{
77        prplcb_ev_timeout_add,
78        b_event_remove,
79        prplcb_ev_input_add,
80        b_event_remove,
81};
82
83static void purple_init( account_t *acc )
84{
85        /* TODO: Figure out variables to export via set. */
86       
87}
88
89static void purple_login( account_t *acc )
90{
91        struct im_connection *ic = imcb_new( acc );
92        PurpleAccount *pa;
93        //PurpleSavedStatus *ps;
94        //GList *i;
95       
96        /* For now this is needed in the _connected() handlers if using
97           GLib event handling, to make sure we're not handling events
98           on dead connections. */
99        purple_connections = g_slist_prepend( purple_connections, ic );
100       
101        pa = purple_account_new( acc->user, acc->prpl->name );
102        purple_account_set_password( pa, acc->pass );
103       
104        ic->proto_data = pa;
105       
106        purple_account_set_enabled( pa, "BitlBee", TRUE );
107       
108        /*
109        for( i = ((PurplePluginProtocolInfo *)pa->gc->prpl->info->extra_info)->protocol_options; i; i = i->next )
110        {
111                PurpleAccountOption *o = i->data;
112               
113                printf( "%s\n", o->pref_name );
114        }
115        */
116       
117        //ps = purple_savedstatus_new( NULL, PURPLE_STATUS_AVAILABLE );
118        //purple_savedstatus_activate_for_account( ps, pa );
119}
120
121static void purple_logout( struct im_connection *ic )
122{
123        purple_connections = g_slist_remove( purple_connections, ic );
124}
125
126static int purple_buddy_msg( struct im_connection *ic, char *who, char *message, int flags )
127{
128        PurpleConversation *conv;
129       
130        if( ( conv = purple_find_conversation_with_account( PURPLE_CONV_TYPE_IM,
131                                                            who, ic->proto_data ) ) == NULL )
132        {
133                conv = purple_conversation_new( PURPLE_CONV_TYPE_IM,
134                                                ic->proto_data, who );
135        }
136       
137        purple_conv_im_send( purple_conversation_get_im_data( conv ), message );
138       
139        return 1;
140}
141
142static GList *purple_away_states( struct im_connection *ic )
143{
144        return NULL;
145}
146
147static void purple_set_away( struct im_connection *ic, char *state_txt, char *message )
148{
149}
150
151static void purple_add_buddy( struct im_connection *ic, char *who, char *group )
152{
153}
154
155static void purple_remove_buddy( struct im_connection *ic, char *who, char *group )
156{
157}
158
159static void purple_keepalive( struct im_connection *ic )
160{
161}
162
163static int purple_send_typing( struct im_connection *ic, char *who, int typing )
164{
165        return 1;
166}
167
168static void purple_ui_init();
169
170static PurpleCoreUiOps bee_core_uiops = 
171{
172        NULL,
173        NULL,
174        purple_ui_init,
175        NULL,
176
177        /* padding */
178        NULL,
179        NULL,
180        NULL,
181        NULL
182};
183
184static void prplcb_conn_progress( PurpleConnection *gc, const char *text, size_t step, size_t step_count )
185{
186        struct im_connection *ic = purple_ic_by_gc( gc );
187       
188        imcb_log( ic, "%s", text );
189}
190
191static void prplcb_conn_connected( PurpleConnection *gc )
192{
193        struct im_connection *ic = purple_ic_by_gc( gc );
194       
195        imcb_connected( ic );
196       
197        if( gc->flags & PURPLE_CONNECTION_HTML )
198                ic->flags |= OPT_DOES_HTML;
199}
200
201static void prplcb_conn_disconnected( PurpleConnection *gc )
202{
203        struct im_connection *ic = purple_ic_by_gc( gc );
204       
205        if( ic != NULL )
206                imc_logout( ic, TRUE );
207}
208
209static void prplcb_conn_notice( PurpleConnection *gc, const char *text )
210{
211        struct im_connection *ic = purple_ic_by_gc( gc );
212       
213        if( ic != NULL )
214                imcb_log( ic, "%s", text );
215}
216
217static void prplcb_conn_report_disconnect_reason( PurpleConnection *gc, PurpleConnectionError reason, const char *text )
218{
219        struct im_connection *ic = purple_ic_by_gc( gc );
220       
221        /* PURPLE_CONNECTION_ERROR_NAME_IN_USE means concurrent login,
222           should probably handle that. */
223        if( ic != NULL )
224                imcb_error( ic, "%s", text );
225}
226
227static PurpleConnectionUiOps bee_conn_uiops =
228{
229        prplcb_conn_progress,
230        prplcb_conn_connected,
231        prplcb_conn_disconnected,
232        prplcb_conn_notice,
233        NULL,
234        NULL,
235        NULL,
236        prplcb_conn_report_disconnect_reason,
237};
238
239static void prplcb_blist_new( PurpleBlistNode *node )
240{
241        PurpleBuddy *bud = (PurpleBuddy*) node;
242        struct im_connection *ic = purple_ic_by_pa( bud->account );
243       
244        if( node->type == PURPLE_BLIST_BUDDY_NODE && ic != NULL )
245        {
246                imcb_add_buddy( ic, bud->name, NULL );
247                if( bud->server_alias )
248                        imcb_buddy_nick_hint( ic, bud->name, bud->server_alias );
249        }
250}
251
252static void prplcb_blist_update( PurpleBuddyList *list, PurpleBlistNode *node )
253{
254        PurpleBuddy *bud = (PurpleBuddy*) node;
255        struct im_connection *ic = purple_ic_by_pa( bud->account );
256       
257        if( node->type == PURPLE_BLIST_BUDDY_NODE && ic != NULL  )
258        {
259                imcb_buddy_status( ic, bud->name,
260                                   purple_presence_is_online( bud->presence ) ? OPT_LOGGED_IN : 0,
261                                   NULL, NULL );
262        }
263}
264
265static void prplcb_blist_remove( PurpleBuddyList *list, PurpleBlistNode *node )
266{
267        PurpleBuddy *bud = (PurpleBuddy*) node;
268        struct im_connection *ic = purple_ic_by_pa( bud->account );
269       
270        if( node->type == PURPLE_BLIST_BUDDY_NODE && ic != NULL  )
271        {
272                imcb_remove_buddy( ic, bud->name, NULL );
273        }
274}
275
276static PurpleBlistUiOps bee_blist_uiops =
277{
278        NULL,
279        prplcb_blist_new,
280        NULL,
281        prplcb_blist_update,
282        prplcb_blist_remove,
283};
284
285static void prplcb_conv_im( PurpleConversation *conv, const char *who, const char *message, PurpleMessageFlags flags, time_t mtime )
286{
287        struct im_connection *ic = purple_ic_by_pa( conv->account );
288       
289        /* ..._SEND means it's an outgoing message, no need to echo those. */
290        if( !( flags & PURPLE_MESSAGE_SEND ) )
291                imcb_buddy_msg( ic, (char*) who, (char*) message, 0, mtime );
292}
293
294static PurpleConversationUiOps bee_conv_uiops = 
295{
296        NULL,                      /* create_conversation  */
297        NULL,                      /* destroy_conversation */
298        NULL,                      /* write_chat           */
299        prplcb_conv_im,            /* write_im             */
300        NULL,                      /* write_conv           */
301        NULL,                      /* chat_add_users       */
302        NULL,                      /* chat_rename_user     */
303        NULL,                      /* chat_remove_users    */
304        NULL,                      /* chat_update_user     */
305        NULL,                      /* present              */
306        NULL,                      /* has_focus            */
307        NULL,                      /* custom_smiley_add    */
308        NULL,                      /* custom_smiley_write  */
309        NULL,                      /* custom_smiley_close  */
310        NULL,                      /* send_confirm         */
311        NULL,
312        NULL,
313        NULL,
314        NULL
315};
316
317static void prplcb_debug_print( PurpleDebugLevel level, const char *category, const char *arg_s )
318{
319        printf( "DEBUG %s: %s", category, arg_s );
320}
321
322static PurpleDebugUiOps bee_debug_uiops =
323{
324        prplcb_debug_print,
325};
326
327static void purple_ui_init()
328{
329        purple_blist_set_ui_ops( &bee_blist_uiops );
330        purple_connections_set_ui_ops( &bee_conn_uiops );
331        purple_conversations_set_ui_ops( &bee_conv_uiops );
332        //purple_debug_set_ui_ops( &bee_debug_uiops );
333}
334
335void purple_initmodule()
336{
337        GList *prots;
338       
339        if( B_EV_IO_READ != PURPLE_INPUT_READ ||
340            B_EV_IO_WRITE != PURPLE_INPUT_WRITE )
341        {
342                /* FIXME FIXME FIXME FIXME FIXME :-) */
343                exit( 1 );
344        }
345       
346        purple_util_set_user_dir("/tmp");
347        purple_debug_set_enabled(FALSE);
348        purple_core_set_ui_ops(&bee_core_uiops);
349        purple_eventloop_set_ui_ops(&glib_eventloops);
350        if( !purple_core_init( "BitlBee") )
351        {
352                /* Initializing the core failed. Terminate. */
353                fprintf( stderr, "libpurple initialization failed.\n" );
354                abort();
355        }
356       
357        /* This seems like stateful shit we don't want... */
358        purple_set_blist(purple_blist_new());
359        purple_blist_load();
360       
361        /* Meh? */
362        purple_prefs_load();
363       
364        for( prots = purple_plugins_get_protocols(); prots; prots = prots->next )
365        {
366                struct prpl *ret = g_new0( struct prpl, 1 );
367                PurplePlugin *prot = prots->data;
368               
369                ret->name = prot->info->id;
370                ret->login = purple_login;
371                ret->init = purple_init;
372                ret->logout = purple_logout;
373                ret->buddy_msg = purple_buddy_msg;
374                ret->away_states = purple_away_states;
375                ret->set_away = purple_set_away;
376                ret->add_buddy = purple_add_buddy;
377                ret->remove_buddy = purple_remove_buddy;
378                ret->keepalive = purple_keepalive;
379                ret->send_typing = purple_send_typing;
380                ret->handle_cmp = g_strcasecmp;
381               
382                register_protocol( ret );
383        }
384}
Note: See TracBrowser for help on using the repository browser.