source: protocols/purple/purple.c @ 0cbef26

Last change on this file since 0cbef26 was 0cbef26, checked in by Wilmer van der Gaast <wilmer@…>, at 2009-10-07T23:37:32Z

Added some debugging stuff and handling (better said, ignoring) of events
for closed connections where necessary.

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