source: protocols/nogaim.c @ 17a6ee9

Last change on this file since 17a6ee9 was 17a6ee9, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-04-11T14:37:06Z

Including DCC stuff again, with a wonderful extra layer of abstraction.
Some hooks are missing so sending files doesn't work yet. Receiving also
still seems to have some issues. On the plus side, at least the MSN/Jabber
modules work again.

  • Property mode set to 100644
File size: 24.1 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/*
8 * nogaim
9 *
10 * Gaim without gaim - for BitlBee
11 *
12 * This file contains functions called by the Gaim IM-modules. It's written
13 * from scratch for BitlBee and doesn't contain any code from Gaim anymore
14 * (except for the function names).
15 */
16
17/*
18  This program is free software; you can redistribute it and/or modify
19  it under the terms of the GNU General Public License as published by
20  the Free Software Foundation; either version 2 of the License, or
21  (at your option) any later version.
22
23  This program is distributed in the hope that it will be useful,
24  but WITHOUT ANY WARRANTY; without even the implied warranty of
25  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  GNU General Public License for more details.
27
28  You should have received a copy of the GNU General Public License with
29  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
30  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
31  Suite 330, Boston, MA  02111-1307  USA
32*/
33
34#define BITLBEE_CORE
35#include <ctype.h>
36
37#include "nogaim.h"
38#include "chat.h"
39
40GSList *connections;
41
42#ifdef WITH_PLUGINS
43gboolean load_plugin(char *path)
44{
45        void (*init_function) (void);
46       
47        GModule *mod = g_module_open(path, G_MODULE_BIND_LAZY);
48
49        if(!mod) {
50                log_message(LOGLVL_ERROR, "Can't find `%s', not loading (%s)\n", path, g_module_error());
51                return FALSE;
52        }
53
54        if(!g_module_symbol(mod,"init_plugin",(gpointer *) &init_function)) {
55                log_message(LOGLVL_WARNING, "Can't find function `init_plugin' in `%s'\n", path);
56                return FALSE;
57        }
58
59        init_function();
60
61        return TRUE;
62}
63
64void load_plugins(void)
65{
66        GDir *dir;
67        GError *error = NULL;
68
69        dir = g_dir_open(global.conf->plugindir, 0, &error);
70
71        if (dir) {
72                const gchar *entry;
73                char *path;
74
75                while ((entry = g_dir_read_name(dir))) {
76                        path = g_build_filename(global.conf->plugindir, entry, NULL);
77                        if(!path) {
78                                log_message(LOGLVL_WARNING, "Can't build path for %s\n", entry);
79                                continue;
80                        }
81
82                        load_plugin(path);
83
84                        g_free(path);
85                }
86
87                g_dir_close(dir);
88        }
89}
90#endif
91
92GList *protocols = NULL;
93 
94void register_protocol (struct prpl *p)
95{
96        int i;
97        gboolean refused = global.conf->protocols != NULL;
98 
99        for (i = 0; global.conf->protocols && global.conf->protocols[i]; i++)
100        {
101                if (g_strcasecmp(p->name, global.conf->protocols[i]) == 0)
102                        refused = FALSE;
103        }
104
105        if (refused)
106                log_message(LOGLVL_WARNING, "Protocol %s disabled\n", p->name);
107        else
108                protocols = g_list_append(protocols, p);
109}
110
111struct prpl *find_protocol(const char *name)
112{
113        GList *gl;
114        for (gl = protocols; gl; gl = gl->next) 
115        {
116                struct prpl *proto = gl->data;
117                if(!g_strcasecmp(proto->name, name)) 
118                        return proto;
119        }
120        return NULL;
121}
122
123void nogaim_init()
124{
125        extern void msn_initmodule();
126        extern void oscar_initmodule();
127        extern void byahoo_initmodule();
128        extern void jabber_initmodule();
129
130#ifdef WITH_MSN
131        msn_initmodule();
132#endif
133
134#ifdef WITH_OSCAR
135        oscar_initmodule();
136#endif
137       
138#ifdef WITH_YAHOO
139        byahoo_initmodule();
140#endif
141       
142#ifdef WITH_JABBER
143        jabber_initmodule();
144#endif
145
146#ifdef WITH_PLUGINS
147        load_plugins();
148#endif
149}
150
151GSList *get_connections() { return connections; }
152
153struct im_connection *imcb_new( account_t *acc )
154{
155        struct im_connection *ic;
156       
157        ic = g_new0( struct im_connection, 1 );
158       
159        ic->bee = acc->bee;
160        ic->acc = acc;
161        acc->ic = ic;
162       
163        connections = g_slist_append( connections, ic );
164       
165        return( ic );
166}
167
168void imc_free( struct im_connection *ic )
169{
170        account_t *a;
171       
172        /* Destroy the pointer to this connection from the account list */
173        for( a = ic->bee->accounts; a; a = a->next )
174                if( a->ic == ic )
175                {
176                        a->ic = NULL;
177                        break;
178                }
179       
180        connections = g_slist_remove( connections, ic );
181        g_free( ic );
182}
183
184static void serv_got_crap( struct im_connection *ic, char *format, ... )
185{
186        va_list params;
187        char *text;
188        account_t *a;
189       
190        va_start( params, format );
191        text = g_strdup_vprintf( format, params );
192        va_end( params );
193
194        if( ( g_strcasecmp( set_getstr( &ic->bee->set, "strip_html" ), "always" ) == 0 ) ||
195            ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->bee->set, "strip_html" ) ) )
196                strip_html( text );
197       
198        /* Try to find a different connection on the same protocol. */
199        for( a = ic->bee->accounts; a; a = a->next )
200                if( a->prpl == ic->acc->prpl && a->ic != ic )
201                        break;
202       
203        /* If we found one, include the screenname in the message. */
204        if( a )
205                /* FIXME(wilmer): ui_log callback or so */
206                irc_usermsg( ic->bee->ui_data, "%s(%s) - %s", ic->acc->prpl->name, ic->acc->user, text );
207        else
208                irc_usermsg( ic->bee->ui_data, "%s - %s", ic->acc->prpl->name, text );
209       
210        g_free( text );
211}
212
213void imcb_log( struct im_connection *ic, char *format, ... )
214{
215        va_list params;
216        char *text;
217       
218        va_start( params, format );
219        text = g_strdup_vprintf( format, params );
220        va_end( params );
221       
222        if( ic->flags & OPT_LOGGED_IN )
223                serv_got_crap( ic, "%s", text );
224        else
225                serv_got_crap( ic, "Logging in: %s", text );
226       
227        g_free( text );
228}
229
230void imcb_error( struct im_connection *ic, char *format, ... )
231{
232        va_list params;
233        char *text;
234       
235        va_start( params, format );
236        text = g_strdup_vprintf( format, params );
237        va_end( params );
238       
239        if( ic->flags & OPT_LOGGED_IN )
240                serv_got_crap( ic, "Error: %s", text );
241        else
242                serv_got_crap( ic, "Couldn't log in: %s", text );
243       
244        g_free( text );
245}
246
247static gboolean send_keepalive( gpointer d, gint fd, b_input_condition cond )
248{
249        struct im_connection *ic = d;
250       
251        if( ic->acc->prpl->keepalive )
252                ic->acc->prpl->keepalive( ic );
253       
254        return TRUE;
255}
256
257void imcb_connected( struct im_connection *ic )
258{
259        /* MSN servers sometimes redirect you to a different server and do
260           the whole login sequence again, so these "late" calls to this
261           function should be handled correctly. (IOW, ignored) */
262        if( ic->flags & OPT_LOGGED_IN )
263                return;
264       
265        imcb_log( ic, "Logged in" );
266       
267        ic->keepalive = b_timeout_add( 60000, send_keepalive, ic );
268        ic->flags |= OPT_LOGGED_IN;
269       
270        /* Necessary to send initial presence status, even if we're not away. */
271        imc_away_send_update( ic );
272       
273        /* Apparently we're connected successfully, so reset the
274           exponential backoff timer. */
275        ic->acc->auto_reconnect_delay = 0;
276       
277        /*
278        for( c = irc->chatrooms; c; c = c->next )
279        {
280                if( c->acc != ic->acc )
281                        continue;
282               
283                if( set_getbool( &c->set, "auto_join" ) )
284                        chat_join( irc, c, NULL );
285        }
286        */
287}
288
289gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond )
290{
291        account_t *a = data;
292       
293        a->reconnect = 0;
294        account_on( a->bee, a );
295       
296        return( FALSE );        /* Only have to run the timeout once */
297}
298
299void cancel_auto_reconnect( account_t *a )
300{
301        b_event_remove( a->reconnect );
302        a->reconnect = 0;
303}
304
305void imc_logout( struct im_connection *ic, int allow_reconnect )
306{
307        bee_t *bee = ic->bee;
308        account_t *a;
309        GSList *l;
310        int delay;
311       
312        /* Nested calls might happen sometimes, this is probably the best
313           place to catch them. */
314        if( ic->flags & OPT_LOGGING_OUT )
315                return;
316        else
317                ic->flags |= OPT_LOGGING_OUT;
318       
319        imcb_log( ic, "Signing off.." );
320       
321        b_event_remove( ic->keepalive );
322        ic->keepalive = 0;
323        ic->acc->prpl->logout( ic );
324        b_event_remove( ic->inpa );
325       
326        g_free( ic->away );
327        ic->away = NULL;
328       
329        for( l = bee->users; l; l = l->next )
330        {
331                bee_user_t *bu = l->data;
332               
333                if( bu->ic == ic )
334                        bee_user_free( bee, ic, bu->handle );
335        }
336       
337        //query_del_by_conn( ic->irc, ic );
338       
339        for( a = bee->accounts; a; a = a->next )
340                if( a->ic == ic )
341                        break;
342       
343        if( !a )
344        {
345                /* Uhm... This is very sick. */
346        }
347        else if( allow_reconnect && set_getbool( &bee->set, "auto_reconnect" ) &&
348                 set_getbool( &a->set, "auto_reconnect" ) &&
349                 ( delay = account_reconnect_delay( a ) ) > 0 )
350        {
351                imcb_log( ic, "Reconnecting in %d seconds..", delay );
352                a->reconnect = b_timeout_add( delay * 1000, auto_reconnect, a );
353        }
354       
355        imc_free( ic );
356}
357
358void imcb_ask( struct im_connection *ic, char *msg, void *data,
359               query_callback doit, query_callback dont )
360{
361        //query_add( ic->irc, ic, msg, doit, dont, data );
362}
363
364void imcb_add_buddy( struct im_connection *ic, const char *handle, const char *group )
365{
366        bee_user_t *bu;
367        bee_t *bee = ic->bee;
368       
369        if( bee_user_by_handle( bee, ic, handle ) )
370        {
371                if( set_getbool( &bee->set, "debug" ) )
372                        imcb_log( ic, "User already exists, ignoring add request: %s", handle );
373               
374                return;
375               
376                /* Buddy seems to exist already. Let's ignore this request then...
377                   Eventually subsequent calls to this function *should* be possible
378                   when a buddy is in multiple groups. But for now BitlBee doesn't
379                   even support groups so let's silently ignore this for now. */
380        }
381       
382        bu = bee_user_new( bee, ic, handle );
383        bu->group = g_strdup( group );
384}
385
386void imcb_rename_buddy( struct im_connection *ic, const char *handle, const char *fullname )
387{
388        bee_t *bee = ic->bee;
389        bee_user_t *bu = bee_user_by_handle( bee, ic, handle );
390       
391        if( !bu || !fullname ) return;
392       
393        if( !bu->fullname || strcmp( bu->fullname, fullname ) != 0 )
394        {
395                g_free( bu->fullname );
396                bu->fullname = g_strdup( fullname );
397               
398                if( bee->ui->user_fullname )
399                        bee->ui->user_fullname( bee, bu );
400        }
401}
402
403void imcb_remove_buddy( struct im_connection *ic, const char *handle, char *group )
404{
405        bee_user_free( ic->bee, ic, handle );
406}
407
408/* Mainly meant for ICQ (and now also for Jabber conferences) to allow IM
409   modules to suggest a nickname for a handle. */
410void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick )
411{
412#if 0
413        user_t *u = user_findhandle( ic, handle );
414        char newnick[MAX_NICK_LENGTH+1], *orig_nick;
415       
416        if( u && !u->online && !nick_saved( ic->acc, handle ) )
417        {
418                /* Only do this if the person isn't online yet (which should
419                   be the case if we just added it) and if the user hasn't
420                   assigned a nickname to this buddy already. */
421               
422                strncpy( newnick, nick, MAX_NICK_LENGTH );
423                newnick[MAX_NICK_LENGTH] = 0;
424               
425                /* Some processing to make sure this string is a valid IRC nickname. */
426                nick_strip( newnick );
427                if( set_getbool( &ic->bee->set, "lcnicks" ) )
428                        nick_lc( newnick );
429               
430                if( strcmp( u->nick, newnick ) != 0 )
431                {
432                        /* Only do this if newnick is different from the current one.
433                           If rejoining a channel, maybe we got this nick already
434                           (and dedupe would only add an underscore. */
435                        nick_dedupe( ic->acc, handle, newnick );
436                       
437                        /* u->nick will be freed halfway the process, so it can't be
438                           passed as an argument. */
439                        orig_nick = g_strdup( u->nick );
440                        user_rename( ic->irc, orig_nick, newnick );
441                        g_free( orig_nick );
442                }
443        }
444#endif
445}
446
447
448struct imcb_ask_cb_data
449{
450        struct im_connection *ic;
451        char *handle;
452};
453
454#if 0
455static void imcb_ask_auth_cb_no( void *data )
456{
457        struct imcb_ask_cb_data *cbd = data;
458       
459        cbd->ic->acc->prpl->auth_deny( cbd->ic, cbd->handle );
460       
461        g_free( cbd->handle );
462        g_free( cbd );
463}
464
465static void imcb_ask_auth_cb_yes( void *data )
466{
467        struct imcb_ask_cb_data *cbd = data;
468       
469        cbd->ic->acc->prpl->auth_allow( cbd->ic, cbd->handle );
470       
471        g_free( cbd->handle );
472        g_free( cbd );
473}
474#endif
475
476void imcb_ask_auth( struct im_connection *ic, const char *handle, const char *realname )
477{
478#if 0
479        struct imcb_ask_cb_data *data = g_new0( struct imcb_ask_cb_data, 1 );
480        char *s, *realname_ = NULL;
481       
482        if( realname != NULL )
483                realname_ = g_strdup_printf( " (%s)", realname );
484       
485        s = g_strdup_printf( "The user %s%s wants to add you to his/her buddy list.",
486                             handle, realname_ ?: "" );
487       
488        g_free( realname_ );
489       
490        data->ic = ic;
491        data->handle = g_strdup( handle );
492        query_add( ic->irc, ic, s, imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, data );
493#endif
494}
495
496
497#if 0
498static void imcb_ask_add_cb_no( void *data )
499{
500        g_free( ((struct imcb_ask_cb_data*)data)->handle );
501        g_free( data );
502}
503
504static void imcb_ask_add_cb_yes( void *data )
505{
506        struct imcb_ask_cb_data *cbd = data;
507       
508        cbd->ic->acc->prpl->add_buddy( cbd->ic, cbd->handle, NULL );
509       
510        return imcb_ask_add_cb_no( data );
511}
512#endif
513
514void imcb_ask_add( struct im_connection *ic, const char *handle, const char *realname )
515{
516#if 0
517        struct imcb_ask_cb_data *data = g_new0( struct imcb_ask_cb_data, 1 );
518        char *s;
519       
520        /* TODO: Make a setting for this! */
521        if( user_findhandle( ic, handle ) != NULL )
522                return;
523       
524        s = g_strdup_printf( "The user %s is not in your buddy list yet. Do you want to add him/her now?", handle );
525       
526        data->ic = ic;
527        data->handle = g_strdup( handle );
528        query_add( ic->irc, ic, s, imcb_ask_add_cb_yes, imcb_ask_add_cb_no, data );
529#endif
530}
531
532void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags )
533{
534#if 0
535        user_t *u;
536       
537        if( !set_getbool( &ic->bee->set, "typing_notice" ) )
538                return;
539       
540        if( ( u = user_findhandle( ic, handle ) ) )
541        {
542                char buf[256];
543               
544                g_snprintf( buf, 256, "\1TYPING %d\1", ( flags >> 8 ) & 3 );
545                irc_privmsg( ic->irc, u, "PRIVMSG", ic->irc->nick, NULL, buf );
546        }
547#endif
548}
549
550struct bee_user *imcb_buddy_by_handle( struct im_connection *ic, const char *handle )
551{
552        return bee_user_by_handle( ic->bee, ic, handle );
553}
554
555struct groupchat *imcb_chat_new( struct im_connection *ic, const char *handle )
556{
557#if 0
558        struct groupchat *c;
559       
560        /* This one just creates the conversation structure, user won't see anything yet */
561       
562        if( ic->groupchats )
563        {
564                for( c = ic->groupchats; c->next; c = c->next );
565                c = c->next = g_new0( struct groupchat, 1 );
566        }
567        else
568                ic->groupchats = c = g_new0( struct groupchat, 1 );
569       
570        c->ic = ic;
571        c->title = g_strdup( handle );
572        c->channel = g_strdup_printf( "&chat_%03d", ic->irc->c_id++ );
573        c->topic = g_strdup_printf( "BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!", c->title );
574       
575        if( set_getbool( &ic->bee->set, "debug" ) )
576                imcb_log( ic, "Creating new conversation: (id=%p,handle=%s)", c, handle );
577       
578        return c;
579#endif
580        return NULL;
581}
582
583void imcb_chat_free( struct groupchat *c )
584{
585#if 0
586        struct im_connection *ic = c->ic;
587        struct groupchat *l;
588        GList *ir;
589       
590        if( set_getbool( &ic->bee->set, "debug" ) )
591                imcb_log( ic, "You were removed from conversation %p", c );
592       
593        if( c )
594        {
595                if( c->joined )
596                {
597                        user_t *u, *r;
598                       
599                        r = user_find( ic->irc, ic->irc->mynick );
600                        irc_privmsg( ic->irc, r, "PRIVMSG", c->channel, "", "Cleaning up channel, bye!" );
601                       
602                        u = user_find( ic->irc, ic->irc->nick );
603                        irc_kick( ic->irc, u, c->channel, r );
604                        /* irc_part( ic->irc, u, c->channel ); */
605                }
606               
607                /* Find the previous chat in the linked list. */
608                for( l = ic->groupchats; l && l->next != c; l = l->next );
609               
610                if( l )
611                        l->next = c->next;
612                else
613                        ic->groupchats = c->next;
614               
615                for( ir = c->in_room; ir; ir = ir->next )
616                        g_free( ir->data );
617                g_list_free( c->in_room );
618                g_free( c->channel );
619                g_free( c->title );
620                g_free( c->topic );
621                g_free( c );
622        }
623#endif
624}
625
626void imcb_chat_msg( struct groupchat *c, const char *who, char *msg, uint32_t flags, time_t sent_at )
627{
628#if 0
629        struct im_connection *ic = c->ic;
630        char *wrapped;
631        user_t *u;
632       
633        /* Gaim sends own messages through this too. IRC doesn't want this, so kill them */
634        if( g_strcasecmp( who, ic->acc->user ) == 0 )
635                return;
636       
637        u = user_findhandle( ic, who );
638       
639        if( ( g_strcasecmp( set_getstr( &ic->bee->set, "strip_html" ), "always" ) == 0 ) ||
640            ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->bee->set, "strip_html" ) ) )
641                strip_html( msg );
642       
643        wrapped = word_wrap( msg, 425 );
644        if( c && u )
645        {
646                irc_privmsg( ic->irc, u, "PRIVMSG", c->channel, "", wrapped );
647        }
648        else
649        {
650                imcb_log( ic, "Message from/to conversation %s@%p (unknown conv/user): %s", who, c, wrapped );
651        }
652        g_free( wrapped );
653#endif
654}
655
656void imcb_chat_log( struct groupchat *c, char *format, ... )
657{
658#if 0
659        irc_t *irc = c->ic->irc;
660        va_list params;
661        char *text;
662        user_t *u;
663       
664        va_start( params, format );
665        text = g_strdup_vprintf( format, params );
666        va_end( params );
667       
668        u = user_find( irc, irc->mynick );
669       
670        irc_privmsg( irc, u, "PRIVMSG", c->channel, "System message: ", text );
671       
672        g_free( text );
673#endif
674}
675
676void imcb_chat_topic( struct groupchat *c, char *who, char *topic, time_t set_at )
677{
678#if 0
679        struct im_connection *ic = c->ic;
680        user_t *u = NULL;
681       
682        if( who == NULL)
683                u = user_find( ic->irc, ic->irc->mynick );
684        else if( g_strcasecmp( who, ic->acc->user ) == 0 )
685                u = user_find( ic->irc, ic->irc->nick );
686        else
687                u = user_findhandle( ic, who );
688       
689        if( ( g_strcasecmp( set_getstr( &ic->bee->set, "strip_html" ), "always" ) == 0 ) ||
690            ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->bee->set, "strip_html" ) ) )
691                strip_html( topic );
692       
693        g_free( c->topic );
694        c->topic = g_strdup( topic );
695       
696        if( c->joined && u )
697                irc_write( ic->irc, ":%s!%s@%s TOPIC %s :%s", u->nick, u->user, u->host, c->channel, topic );
698#endif
699}
700
701void imcb_chat_add_buddy( struct groupchat *b, const char *handle )
702{
703#if 0
704        user_t *u = user_findhandle( b->ic, handle );
705        int me = 0;
706       
707        if( set_getbool( &b->ic->bee->set, "debug" ) )
708                imcb_log( b->ic, "User %s added to conversation %p", handle, b );
709       
710        /* It might be yourself! */
711        if( b->ic->acc->prpl->handle_cmp( handle, b->ic->acc->user ) == 0 )
712        {
713                u = user_find( b->ic->irc, b->ic->irc->nick );
714                if( !b->joined )
715                        irc_join( b->ic->irc, u, b->channel );
716                b->joined = me = 1;
717        }
718       
719        /* Most protocols allow people to join, even when they're not in
720           your contact list. Try to handle that here */
721        if( !u )
722        {
723                imcb_add_buddy( b->ic, handle, NULL );
724                u = user_findhandle( b->ic, handle );
725        }
726       
727        /* Add the handle to the room userlist, if it's not 'me' */
728        if( !me )
729        {
730                if( b->joined )
731                        irc_join( b->ic->irc, u, b->channel );
732                b->in_room = g_list_append( b->in_room, g_strdup( handle ) );
733        }
734#endif
735}
736
737/* This function is one BIG hack... :-( EREWRITE */
738void imcb_chat_remove_buddy( struct groupchat *b, const char *handle, const char *reason )
739{
740#if 0
741        user_t *u;
742        int me = 0;
743       
744        if( set_getbool( &b->ic->bee->set, "debug" ) )
745                imcb_log( b->ic, "User %s removed from conversation %p (%s)", handle, b, reason ? reason : "" );
746       
747        /* It might be yourself! */
748        if( g_strcasecmp( handle, b->ic->acc->user ) == 0 )
749        {
750                if( b->joined == 0 )
751                        return;
752               
753                u = user_find( b->ic->irc, b->ic->irc->nick );
754                b->joined = 0;
755                me = 1;
756        }
757        else
758        {
759                u = user_findhandle( b->ic, handle );
760        }
761       
762        if( me || ( remove_chat_buddy_silent( b, handle ) && b->joined && u ) )
763                irc_part( b->ic->irc, u, b->channel );
764#endif
765}
766
767#if 0
768static int remove_chat_buddy_silent( struct groupchat *b, const char *handle )
769{
770        GList *i;
771       
772        /* Find the handle in the room userlist and shoot it */
773        i = b->in_room;
774        while( i )
775        {
776                if( g_strcasecmp( handle, i->data ) == 0 )
777                {
778                        g_free( i->data );
779                        b->in_room = g_list_remove( b->in_room, i->data );
780                        return( 1 );
781                }
782               
783                i = i->next;
784        }
785       
786        return 0;
787}
788#endif
789
790
791/* Misc. BitlBee stuff which shouldn't really be here */
792#if 0
793char *set_eval_away_devoice( set_t *set, char *value )
794{
795        irc_t *irc = set->data;
796        int st;
797       
798        if( !is_bool( value ) )
799                return SET_INVALID;
800       
801        st = bool2int( value );
802       
803        /* Horror.... */
804       
805        if( st != set_getbool( &irc->b->set, "away_devoice" ) )
806        {
807                char list[80] = "";
808                user_t *u = irc->users;
809                int i = 0, count = 0;
810                char pm;
811                char v[80];
812               
813                if( st )
814                        pm = '+';
815                else
816                        pm = '-';
817               
818                while( u )
819                {
820                        if( u->ic && u->online && !u->away )
821                        {
822                                if( ( strlen( list ) + strlen( u->nick ) ) >= 79 )
823                                {
824                                        for( i = 0; i < count; v[i++] = 'v' ); v[i] = 0;
825                                        irc_write( irc, ":%s MODE %s %c%s%s",
826                                                   irc->myhost,
827                                                   irc->channel, pm, v, list );
828                                       
829                                        *list = 0;
830                                        count = 0;
831                                }
832                               
833                                sprintf( list + strlen( list ), " %s", u->nick );
834                                count ++;
835                        }
836                        u = u->next;
837                }
838               
839                /* $v = 'v' x $i */
840                for( i = 0; i < count; v[i++] = 'v' ); v[i] = 0;
841                irc_write( irc, ":%s MODE %s %c%s%s", irc->myhost,
842                                                            irc->channel, pm, v, list );
843        }
844       
845        return value;
846}
847#endif
848
849
850
851/* The plan is to not allow straight calls to prpl functions anymore, but do
852   them all from some wrappers. We'll start to define some down here: */
853
854int imc_chat_msg( struct groupchat *c, char *msg, int flags )
855{
856        char *buf = NULL;
857       
858        if( ( c->ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )
859        {
860                buf = escape_html( msg );
861                msg = buf;
862        }
863       
864        c->ic->acc->prpl->chat_msg( c, msg, flags );
865        g_free( buf );
866       
867        return 1;
868}
869
870static char *imc_away_state_find( GList *gcm, char *away, char **message );
871
872int imc_away_send_update( struct im_connection *ic )
873{
874        char *away, *msg = NULL;
875       
876        away = set_getstr( &ic->acc->set, "away" ) ?
877             : set_getstr( &ic->bee->set, "away" );
878        if( away && *away )
879        {
880                GList *m = ic->acc->prpl->away_states( ic );
881                msg = ic->acc->flags & ACC_FLAG_AWAY_MESSAGE ? away : NULL;
882                away = imc_away_state_find( m, away, &msg ) ? : m->data;
883        }
884        else if( ic->acc->flags & ACC_FLAG_STATUS_MESSAGE )
885        {
886                away = NULL;
887                msg = set_getstr( &ic->acc->set, "status" ) ?
888                    : set_getstr( &ic->bee->set, "status" );
889        }
890       
891        ic->acc->prpl->set_away( ic, away, msg );
892       
893        return 1;
894}
895
896static char *imc_away_alias_list[8][5] =
897{
898        { "Away from computer", "Away", "Extended away", NULL },
899        { "NA", "N/A", "Not available", NULL },
900        { "Busy", "Do not disturb", "DND", "Occupied", NULL },
901        { "Be right back", "BRB", NULL },
902        { "On the phone", "Phone", "On phone", NULL },
903        { "Out to lunch", "Lunch", "Food", NULL },
904        { "Invisible", "Hidden" },
905        { NULL }
906};
907
908static char *imc_away_state_find( GList *gcm, char *away, char **message )
909{
910        GList *m;
911        int i, j;
912       
913        for( m = gcm; m; m = m->next )
914                if( g_strncasecmp( m->data, away, strlen( m->data ) ) == 0 )
915                {
916                        /* At least the Yahoo! module works better if message
917                           contains no data unless it adds something to what
918                           we have in state already. */
919                        if( strlen( m->data ) == strlen( away ) )
920                                *message = NULL;
921                       
922                        return m->data;
923                }
924       
925        for( i = 0; *imc_away_alias_list[i]; i ++ )
926        {
927                int keep_message;
928               
929                for( j = 0; imc_away_alias_list[i][j]; j ++ )
930                        if( g_strncasecmp( away, imc_away_alias_list[i][j], strlen( imc_away_alias_list[i][j] ) ) == 0 )
931                        {
932                                keep_message = strlen( away ) != strlen( imc_away_alias_list[i][j] );
933                                break;
934                        }
935               
936                if( !imc_away_alias_list[i][j] )        /* If we reach the end, this row */
937                        continue;                       /* is not what we want. Next!    */
938               
939                /* Now find an entry in this row which exists in gcm */
940                for( j = 0; imc_away_alias_list[i][j]; j ++ )
941                {
942                        for( m = gcm; m; m = m->next )
943                                if( g_strcasecmp( imc_away_alias_list[i][j], m->data ) == 0 )
944                                {
945                                        if( !keep_message )
946                                                *message = NULL;
947                                       
948                                        return imc_away_alias_list[i][j];
949                                }
950                }
951               
952                /* No need to look further, apparently this state doesn't
953                   have any good alias for this protocol. */
954                break;
955        }
956       
957        return NULL;
958}
959
960void imc_add_allow( struct im_connection *ic, char *handle )
961{
962        if( g_slist_find_custom( ic->permit, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) == NULL )
963        {
964                ic->permit = g_slist_prepend( ic->permit, g_strdup( handle ) );
965        }
966       
967        ic->acc->prpl->add_permit( ic, handle );
968}
969
970void imc_rem_allow( struct im_connection *ic, char *handle )
971{
972        GSList *l;
973       
974        if( ( l = g_slist_find_custom( ic->permit, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) ) )
975        {
976                g_free( l->data );
977                ic->permit = g_slist_delete_link( ic->permit, l );
978        }
979       
980        ic->acc->prpl->rem_permit( ic, handle );
981}
982
983void imc_add_block( struct im_connection *ic, char *handle )
984{
985        if( g_slist_find_custom( ic->deny, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) == NULL )
986        {
987                ic->deny = g_slist_prepend( ic->deny, g_strdup( handle ) );
988        }
989       
990        ic->acc->prpl->add_deny( ic, handle );
991}
992
993void imc_rem_block( struct im_connection *ic, char *handle )
994{
995        GSList *l;
996       
997        if( ( l = g_slist_find_custom( ic->deny, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) ) )
998        {
999                g_free( l->data );
1000                ic->deny = g_slist_delete_link( ic->deny, l );
1001        }
1002       
1003        ic->acc->prpl->rem_deny( ic, handle );
1004}
1005
1006void imcb_clean_handle( struct im_connection *ic, char *handle )
1007{
1008        /* Accepts a handle and does whatever is necessary to make it
1009           BitlBee-friendly. Currently this means removing everything
1010           outside 33-127 (ASCII printable excl spaces), @ (only one
1011           is allowed) and ! and : */
1012        char out[strlen(handle)+1];
1013        int s, d;
1014       
1015        s = d = 0;
1016        while( handle[s] )
1017        {
1018                if( handle[s] > ' ' && handle[s] != '!' && handle[s] != ':' &&
1019                    ( handle[s] & 0x80 ) == 0 )
1020                {
1021                        if( handle[s] == '@' )
1022                        {
1023                                /* See if we got an @ already? */
1024                                out[d] = 0;
1025                                if( strchr( out, '@' ) )
1026                                        continue;
1027                        }
1028                       
1029                        out[d++] = handle[s];
1030                }
1031                s ++;
1032        }
1033        out[d] = handle[s];
1034       
1035        strcpy( handle, out );
1036}
Note: See TracBrowser for help on using the repository browser.