source: protocols/nogaim.c @ 85023c6

Last change on this file since 85023c6 was 85023c6, checked in by Wilmer van der Gaast <wilmer@…>, at 2007-07-15T15:47:34Z

Added imcb_clean_handle() to sanitize handles properly (without putting
IRC-specific stuff into the Jabber module). Only using this in the MUC
code for now because this only works if the IM module can somehow convert
the cleaned up handle back to the original one.

  • Property mode set to 100644
File size: 26.2 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2006 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 "nogaim.h"
36#include <ctype.h>
37
38static int remove_chat_buddy_silent( struct groupchat *b, char *handle );
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", path);
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
92/* nogaim.c */
93
94GList *protocols = NULL;
95 
96void register_protocol (struct prpl *p)
97{
98        protocols = g_list_append(protocols, p);
99}
100
101struct prpl *find_protocol(const char *name)
102{
103        GList *gl;
104        for (gl = protocols; gl; gl = gl->next) 
105        {
106                struct prpl *proto = gl->data;
107                if(!g_strcasecmp(proto->name, name)) 
108                        return proto;
109        }
110        return NULL;
111}
112
113/* nogaim.c */
114void nogaim_init()
115{
116        extern void msn_initmodule();
117        extern void oscar_initmodule();
118        extern void byahoo_initmodule();
119        extern void jabber_initmodule();
120
121#ifdef WITH_MSN
122        msn_initmodule();
123#endif
124
125#ifdef WITH_OSCAR
126        oscar_initmodule();
127#endif
128       
129#ifdef WITH_YAHOO
130        byahoo_initmodule();
131#endif
132       
133#ifdef WITH_JABBER
134        jabber_initmodule();
135#endif
136
137#ifdef WITH_PLUGINS
138        load_plugins();
139#endif
140}
141
142GSList *get_connections() { return connections; }
143
144/* multi.c */
145
146struct im_connection *imcb_new( account_t *acc )
147{
148        struct im_connection *ic;
149       
150        ic = g_new0( struct im_connection, 1 );
151       
152        ic->irc = acc->irc;
153        ic->acc = acc;
154        acc->ic = ic;
155       
156        connections = g_slist_append( connections, ic );
157       
158        return( ic );
159}
160
161void imc_free( struct im_connection *ic )
162{
163        account_t *a;
164       
165        /* Destroy the pointer to this connection from the account list */
166        for( a = ic->irc->accounts; a; a = a->next )
167                if( a->ic == ic )
168                {
169                        a->ic = NULL;
170                        break;
171                }
172       
173        connections = g_slist_remove( connections, ic );
174        g_free( ic );
175}
176
177static void serv_got_crap( struct im_connection *ic, char *format, ... )
178{
179        va_list params;
180        char *text;
181        account_t *a;
182       
183        va_start( params, format );
184        text = g_strdup_vprintf( format, params );
185        va_end( params );
186
187        if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
188            ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
189                strip_html( text );
190       
191        /* Try to find a different connection on the same protocol. */
192        for( a = ic->irc->accounts; a; a = a->next )
193                if( a->prpl == ic->acc->prpl && a->ic != ic )
194                        break;
195       
196        /* If we found one, include the screenname in the message. */
197        if( a )
198                irc_usermsg( ic->irc, "%s(%s) - %s", ic->acc->prpl->name, ic->acc->user, text );
199        else
200                irc_usermsg( ic->irc, "%s - %s", ic->acc->prpl->name, text );
201       
202        g_free( text );
203}
204
205void imcb_log( struct im_connection *ic, char *format, ... )
206{
207        va_list params;
208        char *text;
209       
210        va_start( params, format );
211        text = g_strdup_vprintf( format, params );
212        va_end( params );
213       
214        if( ic->flags & OPT_LOGGED_IN )
215                serv_got_crap( ic, "%s", text );
216        else
217                serv_got_crap( ic, "Logging in: %s", text );
218       
219        g_free( text );
220}
221
222void imcb_error( struct im_connection *ic, char *format, ... )
223{
224        va_list params;
225        char *text;
226       
227        va_start( params, format );
228        text = g_strdup_vprintf( format, params );
229        va_end( params );
230       
231        if( ic->flags & OPT_LOGGED_IN )
232                serv_got_crap( ic, "Error: %s", text );
233        else
234                serv_got_crap( ic, "Couldn't log in: %s", text );
235       
236        g_free( text );
237}
238
239static gboolean send_keepalive( gpointer d, gint fd, b_input_condition cond )
240{
241        struct im_connection *ic = d;
242       
243        if( ic->acc->prpl->keepalive )
244                ic->acc->prpl->keepalive( ic );
245       
246        return TRUE;
247}
248
249void imcb_connected( struct im_connection *ic )
250{
251        user_t *u;
252       
253        /* MSN servers sometimes redirect you to a different server and do
254           the whole login sequence again, so these "late" calls to this
255           function should be handled correctly. (IOW, ignored) */
256        if( ic->flags & OPT_LOGGED_IN )
257                return;
258       
259        u = user_find( ic->irc, ic->irc->nick );
260       
261        imcb_log( ic, "Logged in" );
262       
263        ic->keepalive = b_timeout_add( 60000, send_keepalive, ic );
264        ic->flags |= OPT_LOGGED_IN;
265       
266        /* Also necessary when we're not away, at least for some of the
267           protocols. */
268        imc_set_away( ic, u->away );
269}
270
271gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond )
272{
273        account_t *a = data;
274       
275        a->reconnect = 0;
276        account_on( a->irc, a );
277       
278        return( FALSE );        /* Only have to run the timeout once */
279}
280
281void cancel_auto_reconnect( account_t *a )
282{
283        b_event_remove( a->reconnect );
284        a->reconnect = 0;
285}
286
287void imc_logout( struct im_connection *ic, int allow_reconnect )
288{
289        irc_t *irc = ic->irc;
290        user_t *t, *u;
291        account_t *a;
292       
293        /* Nested calls might happen sometimes, this is probably the best
294           place to catch them. */
295        if( ic->flags & OPT_LOGGING_OUT )
296                return;
297        else
298                ic->flags |= OPT_LOGGING_OUT;
299       
300        imcb_log( ic, "Signing off.." );
301       
302        b_event_remove( ic->keepalive );
303        ic->keepalive = 0;
304        ic->acc->prpl->logout( ic );
305        b_event_remove( ic->inpa );
306       
307        u = irc->users;
308        while( u )
309        {
310                if( u->ic == ic )
311                {
312                        t = u->next;
313                        user_del( irc, u->nick );
314                        u = t;
315                }
316                else
317                        u = u->next;
318        }
319       
320        query_del_by_conn( ic->irc, ic );
321       
322        for( a = irc->accounts; a; a = a->next )
323                if( a->ic == ic )
324                        break;
325       
326        if( !a )
327        {
328                /* Uhm... This is very sick. */
329        }
330        else if( allow_reconnect && set_getbool( &irc->set, "auto_reconnect" ) &&
331                 set_getbool( &a->set, "auto_reconnect" ) )
332        {
333                int delay = set_getint( &irc->set, "auto_reconnect_delay" );
334               
335                imcb_log( ic, "Reconnecting in %d seconds..", delay );
336                a->reconnect = b_timeout_add( delay * 1000, auto_reconnect, a );
337        }
338       
339        imc_free( ic );
340}
341
342
343/* dialogs.c */
344
345void imcb_ask( struct im_connection *ic, char *msg, void *data, void *doit, void *dont )
346{
347        query_add( ic->irc, ic, msg, doit, dont, data );
348}
349
350
351/* list.c */
352
353void imcb_add_buddy( struct im_connection *ic, char *handle, char *group )
354{
355        user_t *u;
356        char nick[MAX_NICK_LENGTH+1], *s;
357        irc_t *irc = ic->irc;
358       
359        if( user_findhandle( ic, handle ) )
360        {
361                if( set_getbool( &irc->set, "debug" ) )
362                        imcb_log( ic, "User already exists, ignoring add request: %s", handle );
363               
364                return;
365               
366                /* Buddy seems to exist already. Let's ignore this request then...
367                   Eventually subsequent calls to this function *should* be possible
368                   when a buddy is in multiple groups. But for now BitlBee doesn't
369                   even support groups so let's silently ignore this for now. */
370        }
371       
372        memset( nick, 0, MAX_NICK_LENGTH + 1 );
373        strcpy( nick, nick_get( ic->acc, handle ) );
374       
375        u = user_add( ic->irc, nick );
376       
377//      if( !realname || !*realname ) realname = nick;
378//      u->realname = g_strdup( realname );
379       
380        if( ( s = strchr( handle, '@' ) ) )
381        {
382                u->host = g_strdup( s + 1 );
383                u->user = g_strndup( handle, s - handle );
384        }
385        else if( ic->acc->server )
386        {
387                u->host = g_strdup( ic->acc->server );
388                u->user = g_strdup( handle );
389               
390                /* s/ /_/ ... important for AOL screennames */
391                for( s = u->user; *s; s ++ )
392                        if( *s == ' ' )
393                                *s = '_';
394        }
395        else
396        {
397                u->host = g_strdup( ic->acc->prpl->name );
398                u->user = g_strdup( handle );
399        }
400       
401        u->ic = ic;
402        u->handle = g_strdup( handle );
403        if( group ) u->group = g_strdup( group );
404        u->send_handler = buddy_send_handler;
405        u->last_typing_notice = 0;
406}
407
408struct buddy *imcb_find_buddy( struct im_connection *ic, char *handle )
409{
410        static struct buddy b[1];
411        user_t *u;
412       
413        u = user_findhandle( ic, handle );
414       
415        if( !u )
416                return( NULL );
417       
418        memset( b, 0, sizeof( b ) );
419        strncpy( b->name, handle, 80 );
420        strncpy( b->show, u->realname, BUDDY_ALIAS_MAXLEN );
421        b->present = u->online;
422        b->ic = u->ic;
423       
424        return( b );
425}
426
427void imcb_rename_buddy( struct im_connection *ic, char *handle, char *realname )
428{
429        user_t *u = user_findhandle( ic, handle );
430       
431        if( !u || !realname ) return;
432       
433        if( g_strcasecmp( u->realname, realname ) != 0 )
434        {
435                if( u->realname != u->nick ) g_free( u->realname );
436               
437                u->realname = g_strdup( realname );
438               
439                if( ( ic->flags & OPT_LOGGED_IN ) && set_getbool( &ic->irc->set, "display_namechanges" ) )
440                        imcb_log( ic, "User `%s' changed name to `%s'", u->nick, u->realname );
441        }
442}
443
444void imcb_remove_buddy( struct im_connection *ic, char *handle, char *group )
445{
446        user_t *u;
447       
448        if( ( u = user_findhandle( ic, handle ) ) )
449                user_del( ic->irc, u->nick );
450}
451
452/* Mainly meant for ICQ (and now also for Jabber conferences) to allow IM
453   modules to suggest a nickname for a handle. */
454void imcb_buddy_nick_hint( struct im_connection *ic, char *handle, char *nick )
455{
456        user_t *u = user_findhandle( ic, handle );
457        char newnick[MAX_NICK_LENGTH+1], *orig_nick;
458       
459        if( u && !u->online && !nick_saved( ic->acc, handle ) )
460        {
461                /* Only do this if the person isn't online yet (which should
462                   be the case if we just added it) and if the user hasn't
463                   assigned a nickname to this buddy already. */
464               
465                strncpy( newnick, nick, MAX_NICK_LENGTH );
466                newnick[MAX_NICK_LENGTH] = 0;
467               
468                /* Some processing to make sure this string is a valid IRC nickname. */
469                nick_strip( newnick );
470                if( set_getbool( &ic->irc->set, "lcnicks" ) )
471                        nick_lc( newnick );
472               
473                if( strcmp( u->nick, newnick ) != 0 )
474                {
475                        /* Only do this if newnick is different from the current one.
476                           If rejoining a channel, maybe we got this nick already
477                           (and dedupe would only add an underscore. */
478                        nick_dedupe( ic->acc, handle, newnick );
479                       
480                        /* u->nick will be freed halfway the process, so it can't be
481                           passed as an argument. */
482                        orig_nick = g_strdup( u->nick );
483                        user_rename( ic->irc, orig_nick, newnick );
484                        g_free( orig_nick );
485                }
486        }
487}
488
489/* prpl.c */
490
491struct show_got_added_data
492{
493        struct im_connection *ic;
494        char *handle;
495};
496
497void show_got_added_no( gpointer w, struct show_got_added_data *data )
498{
499        g_free( data->handle );
500        g_free( data );
501}
502
503void show_got_added_yes( gpointer w, struct show_got_added_data *data )
504{
505        data->ic->acc->prpl->add_buddy( data->ic, data->handle, NULL );
506        /* imcb_add_buddy( data->ic, NULL, data->handle, data->handle ); */
507       
508        return show_got_added_no( w, data );
509}
510
511void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname )
512{
513        struct show_got_added_data *data = g_new0( struct show_got_added_data, 1 );
514        char *s;
515       
516        /* TODO: Make a setting for this! */
517        if( user_findhandle( ic, handle ) != NULL )
518                return;
519       
520        s = g_strdup_printf( "The user %s is not in your buddy list yet. Do you want to add him/her now?", handle );
521       
522        data->ic = ic;
523        data->handle = g_strdup( handle );
524        query_add( ic->irc, ic, s, show_got_added_yes, show_got_added_no, data );
525}
526
527
528/* server.c */                   
529
530void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message )
531{
532        user_t *u;
533        int oa, oo;
534       
535        u = user_findhandle( ic, (char*) handle );
536       
537        if( !u )
538        {
539                if( g_strcasecmp( set_getstr( &ic->irc->set, "handle_unknown" ), "add" ) == 0 )
540                {
541                        imcb_add_buddy( ic, (char*) handle, NULL );
542                        u = user_findhandle( ic, (char*) handle );
543                }
544                else
545                {
546                        if( set_getbool( &ic->irc->set, "debug" ) || g_strcasecmp( set_getstr( &ic->irc->set, "handle_unknown" ), "ignore" ) != 0 )
547                        {
548                                imcb_log( ic, "imcb_buddy_status() for unknown handle %s:", handle );
549                                imcb_log( ic, "flags = %d, state = %s, message = %s", flags,
550                                          state ? state : "NULL", message ? message : "NULL" );
551                        }
552                       
553                        return;
554                }
555        }
556       
557        oa = u->away != NULL;
558        oo = u->online;
559       
560        if( u->away )
561        {
562                g_free( u->away );
563                u->away = NULL;
564        }
565       
566        if( ( flags & OPT_LOGGED_IN ) && !u->online )
567        {
568                irc_spawn( ic->irc, u );
569                u->online = 1;
570        }
571        else if( !( flags & OPT_LOGGED_IN ) && u->online )
572        {
573                struct groupchat *c;
574               
575                irc_kill( ic->irc, u );
576                u->online = 0;
577               
578                /* Remove him/her from the groupchats to prevent PART messages after he/she QUIT already */
579                for( c = ic->groupchats; c; c = c->next )
580                        remove_chat_buddy_silent( c, (char*) handle );
581        }
582       
583        if( flags & OPT_AWAY )
584        {
585                if( state && message )
586                {
587                        u->away = g_strdup_printf( "%s (%s)", state, message );
588                }
589                else if( state )
590                {
591                        u->away = g_strdup( state );
592                }
593                else if( message )
594                {
595                        u->away = g_strdup( message );
596                }
597                else
598                {
599                        u->away = g_strdup( "Away" );
600                }
601        }
602        /* else waste_any_state_information_for_now(); */
603       
604        /* LISPy... */
605        if( ( set_getbool( &ic->irc->set, "away_devoice" ) ) &&         /* Don't do a thing when user doesn't want it */
606            ( u->online ) &&                                            /* Don't touch offline people */
607            ( ( ( u->online != oo ) && !u->away ) ||                    /* Voice joining people */
608              ( ( u->online == oo ) && ( oa == !u->away ) ) ) )         /* (De)voice people changing state */
609        {
610                irc_write( ic->irc, ":%s MODE %s %cv %s", ic->irc->myhost,
611                                                          ic->irc->channel, u->away?'-':'+', u->nick );
612        }
613}
614
615void imcb_buddy_msg( struct im_connection *ic, char *handle, char *msg, u_int32_t flags, time_t sent_at )
616{
617        irc_t *irc = ic->irc;
618        user_t *u;
619       
620        u = user_findhandle( ic, handle );
621       
622        if( !u )
623        {
624                char *h = set_getstr( &irc->set, "handle_unknown" );
625               
626                if( g_strcasecmp( h, "ignore" ) == 0 )
627                {
628                        if( set_getbool( &irc->set, "debug" ) )
629                                imcb_log( ic, "Ignoring message from unknown handle %s", handle );
630                       
631                        return;
632                }
633                else if( g_strncasecmp( h, "add", 3 ) == 0 )
634                {
635                        int private = set_getbool( &irc->set, "private" );
636                       
637                        if( h[3] )
638                        {
639                                if( g_strcasecmp( h + 3, "_private" ) == 0 )
640                                        private = 1;
641                                else if( g_strcasecmp( h + 3, "_channel" ) == 0 )
642                                        private = 0;
643                        }
644                       
645                        imcb_add_buddy( ic, handle, NULL );
646                        u = user_findhandle( ic, handle );
647                        u->is_private = private;
648                }
649                else
650                {
651                        imcb_log( ic, "Message from unknown handle %s:", handle );
652                        u = user_find( irc, irc->mynick );
653                }
654        }
655       
656        if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
657            ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
658                strip_html( msg );
659
660        while( strlen( msg ) > 425 )
661        {
662                char tmp, *nl;
663               
664                tmp = msg[425];
665                msg[425] = 0;
666               
667                /* If there's a newline/space in this string, split up there,
668                   looks a bit prettier. */
669                if( ( nl = strrchr( msg, '\n' ) ) || ( nl = strrchr( msg, ' ' ) ) )
670                {
671                        msg[425] = tmp;
672                        tmp = *nl;
673                        *nl = 0;
674                }
675               
676                irc_msgfrom( irc, u->nick, msg );
677               
678                /* Move on. */
679                if( nl )
680                {
681                        *nl = tmp;
682                        msg = nl + 1;
683                }
684                else
685                {
686                        msg[425] = tmp;
687                        msg += 425;
688                }
689        }
690        irc_msgfrom( irc, u->nick, msg );
691}
692
693void imcb_buddy_typing( struct im_connection *ic, char *handle, u_int32_t flags )
694{
695        user_t *u;
696       
697        if( !set_getbool( &ic->irc->set, "typing_notice" ) )
698                return;
699       
700        if( ( u = user_findhandle( ic, handle ) ) )
701        {
702                char buf[256]; 
703               
704                g_snprintf( buf, 256, "\1TYPING %d\1", ( flags >> 8 ) & 3 );
705                irc_privmsg( ic->irc, u, "PRIVMSG", ic->irc->nick, NULL, buf );
706        }
707}
708
709void imcb_chat_free( struct groupchat *c )
710{
711        struct im_connection *ic = c->ic;
712        struct groupchat *l;
713        GList *ir;
714       
715        if( set_getbool( &ic->irc->set, "debug" ) )
716                imcb_log( ic, "You were removed from conversation 0x%x", (int) c );
717       
718        if( c )
719        {
720                if( c->joined )
721                {
722                        user_t *u, *r;
723                       
724                        r = user_find( ic->irc, ic->irc->mynick );
725                        irc_privmsg( ic->irc, r, "PRIVMSG", c->channel, "", "Cleaning up channel, bye!" );
726                       
727                        u = user_find( ic->irc, ic->irc->nick );
728                        irc_kick( ic->irc, u, c->channel, r );
729                        /* irc_part( ic->irc, u, c->channel ); */
730                }
731               
732                /* Find the previous chat in the linked list. */
733                for( l = ic->groupchats; l && l->next != c; l = l->next );
734               
735                if( l )
736                        l->next = c->next;
737                else
738                        ic->groupchats = c->next;
739               
740                for( ir = c->in_room; ir; ir = ir->next )
741                        g_free( ir->data );
742                g_list_free( c->in_room );
743                g_free( c->channel );
744                g_free( c->title );
745                g_free( c );
746        }
747}
748
749void imcb_chat_msg( struct groupchat *c, char *who, char *msg, u_int32_t flags, time_t sent_at )
750{
751        struct im_connection *ic = c->ic;
752        user_t *u;
753       
754        /* Gaim sends own messages through this too. IRC doesn't want this, so kill them */
755        if( g_strcasecmp( who, ic->acc->user ) == 0 )
756                return;
757       
758        u = user_findhandle( ic, who );
759       
760        if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
761            ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
762                strip_html( msg );
763       
764        if( c && u )
765                irc_privmsg( ic->irc, u, "PRIVMSG", c->channel, "", msg );
766        else
767                imcb_log( ic, "Message from/to conversation %s@0x%x (unknown conv/user): %s", who, (int) c, msg );
768}
769
770struct groupchat *imcb_chat_new( struct im_connection *ic, char *handle )
771{
772        struct groupchat *c;
773       
774        /* This one just creates the conversation structure, user won't see anything yet */
775       
776        if( ic->groupchats )
777        {
778                for( c = ic->groupchats; c->next; c = c->next );
779                c = c->next = g_new0( struct groupchat, 1 );
780        }
781        else
782                ic->groupchats = c = g_new0( struct groupchat, 1 );
783       
784        c->ic = ic;
785        c->title = g_strdup( handle );
786        c->channel = g_strdup_printf( "&chat_%03d", ic->irc->c_id++ );
787       
788        if( set_getbool( &ic->irc->set, "debug" ) )
789                imcb_log( ic, "Creating new conversation: (id=0x%x,handle=%s)", (int) c, handle );
790       
791        return c;
792}
793
794
795/* buddy_chat.c */
796
797void imcb_chat_add_buddy( struct groupchat *b, char *handle )
798{
799        user_t *u = user_findhandle( b->ic, handle );
800        int me = 0;
801       
802        if( set_getbool( &b->ic->irc->set, "debug" ) )
803                imcb_log( b->ic, "User %s added to conversation 0x%x", handle, (int) b );
804       
805        /* It might be yourself! */
806        if( b->ic->acc->prpl->handle_cmp( handle, b->ic->acc->user ) == 0 )
807        {
808                u = user_find( b->ic->irc, b->ic->irc->nick );
809                if( !b->joined )
810                        irc_join( b->ic->irc, u, b->channel );
811                b->joined = me = 1;
812        }
813       
814        /* Most protocols allow people to join, even when they're not in
815           your contact list. Try to handle that here */
816        if( !u )
817        {
818                imcb_add_buddy( b->ic, handle, NULL );
819                u = user_findhandle( b->ic, handle );
820        }
821       
822        /* Add the handle to the room userlist, if it's not 'me' */
823        if( !me )
824        {
825                if( b->joined )
826                        irc_join( b->ic->irc, u, b->channel );
827                b->in_room = g_list_append( b->in_room, g_strdup( handle ) );
828        }
829}
830
831/* This function is one BIG hack... :-( EREWRITE */
832void imcb_chat_remove_buddy( struct groupchat *b, char *handle, char *reason )
833{
834        user_t *u;
835        int me = 0;
836       
837        if( set_getbool( &b->ic->irc->set, "debug" ) )
838                imcb_log( b->ic, "User %s removed from conversation 0x%x (%s)", handle, (int) b, reason ? reason : "" );
839       
840        /* It might be yourself! */
841        if( g_strcasecmp( handle, b->ic->acc->user ) == 0 )
842        {
843                if( b->joined == 0 )
844                        return;
845               
846                u = user_find( b->ic->irc, b->ic->irc->nick );
847                b->joined = 0;
848                me = 1;
849        }
850        else
851        {
852                u = user_findhandle( b->ic, handle );
853        }
854       
855        if( me || ( remove_chat_buddy_silent( b, handle ) && b->joined && u ) )
856                irc_part( b->ic->irc, u, b->channel );
857}
858
859static int remove_chat_buddy_silent( struct groupchat *b, char *handle )
860{
861        GList *i;
862       
863        /* Find the handle in the room userlist and shoot it */
864        i = b->in_room;
865        while( i )
866        {
867                if( g_strcasecmp( handle, i->data ) == 0 )
868                {
869                        g_free( i->data );
870                        b->in_room = g_list_remove( b->in_room, i->data );
871                        return( 1 );
872                }
873               
874                i = i->next;
875        }
876       
877        return( 0 );
878}
879
880
881/* Misc. BitlBee stuff which shouldn't really be here */
882
883char *set_eval_away_devoice( set_t *set, char *value )
884{
885        irc_t *irc = set->data;
886        int st;
887       
888        if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) )
889                st = 1;
890        else if( ( g_strcasecmp( value, "false" ) == 0 ) || ( g_strcasecmp( value, "no" ) == 0 ) || ( g_strcasecmp( value, "off" ) == 0 ) )
891                st = 0;
892        else if( sscanf( value, "%d", &st ) != 1 )
893                return( NULL );
894       
895        st = st != 0;
896       
897        /* Horror.... */
898       
899        if( st != set_getbool( &irc->set, "away_devoice" ) )
900        {
901                char list[80] = "";
902                user_t *u = irc->users;
903                int i = 0, count = 0;
904                char pm;
905                char v[80];
906               
907                if( st )
908                        pm = '+';
909                else
910                        pm = '-';
911               
912                while( u )
913                {
914                        if( u->ic && u->online && !u->away )
915                        {
916                                if( ( strlen( list ) + strlen( u->nick ) ) >= 79 )
917                                {
918                                        for( i = 0; i < count; v[i++] = 'v' ); v[i] = 0;
919                                        irc_write( irc, ":%s MODE %s %c%s%s",
920                                                   irc->myhost,
921                                                   irc->channel, pm, v, list );
922                                       
923                                        *list = 0;
924                                        count = 0;
925                                }
926                               
927                                sprintf( list + strlen( list ), " %s", u->nick );
928                                count ++;
929                        }
930                        u = u->next;
931                }
932               
933                /* $v = 'v' x $i */
934                for( i = 0; i < count; v[i++] = 'v' ); v[i] = 0;
935                irc_write( irc, ":%s MODE %s %c%s%s", irc->myhost,
936                                                            irc->channel, pm, v, list );
937        }
938       
939        return( set_eval_bool( set, value ) );
940}
941
942
943
944
945/* The plan is to not allow straight calls to prpl functions anymore, but do
946   them all from some wrappers. We'll start to define some down here: */
947
948int imc_buddy_msg( struct im_connection *ic, char *handle, char *msg, int flags )
949{
950        char *buf = NULL;
951        int st;
952       
953        if( ( ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )
954        {
955                buf = escape_html( msg );
956                msg = buf;
957        }
958       
959        st = ic->acc->prpl->buddy_msg( ic, handle, msg, flags );
960        g_free( buf );
961       
962        return st;
963}
964
965int imc_chat_msg( struct groupchat *c, char *msg, int flags )
966{
967        char *buf = NULL;
968       
969        if( ( c->ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )
970        {
971                buf = escape_html( msg );
972                msg = buf;
973        }
974       
975        c->ic->acc->prpl->chat_msg( c, msg, flags );
976        g_free( buf );
977       
978        return 1;
979}
980
981static char *imc_away_alias_find( GList *gcm, char *away );
982
983int imc_set_away( struct im_connection *ic, char *away )
984{
985        GList *m, *ms;
986        char *s;
987       
988        if( !away ) away = "";
989        ms = m = ic->acc->prpl->away_states( ic );
990       
991        while( m )
992        {
993                if( *away )
994                {
995                        if( g_strncasecmp( m->data, away, strlen( m->data ) ) == 0 )
996                                break;
997                }
998                else
999                {
1000                        if( g_strcasecmp( m->data, "Available" ) == 0 )
1001                                break;
1002                        if( g_strcasecmp( m->data, "Online" ) == 0 )
1003                                break;
1004                }
1005                m = m->next;
1006        }
1007       
1008        if( m )
1009        {
1010                ic->acc->prpl->set_away( ic, m->data, *away ? away : NULL );
1011        }
1012        else
1013        {
1014                s = imc_away_alias_find( ms, away );
1015                if( s )
1016                {
1017                        ic->acc->prpl->set_away( ic, s, away );
1018                        if( set_getbool( &ic->irc->set, "debug" ) )
1019                                imcb_log( ic, "Setting away state to %s", s );
1020                }
1021                else
1022                        ic->acc->prpl->set_away( ic, GAIM_AWAY_CUSTOM, away );
1023        }
1024       
1025        return( 1 );
1026}
1027
1028static char *imc_away_alias_list[8][5] =
1029{
1030        { "Away from computer", "Away", "Extended away", NULL },
1031        { "NA", "N/A", "Not available", NULL },
1032        { "Busy", "Do not disturb", "DND", "Occupied", NULL },
1033        { "Be right back", "BRB", NULL },
1034        { "On the phone", "Phone", "On phone", NULL },
1035        { "Out to lunch", "Lunch", "Food", NULL },
1036        { "Invisible", "Hidden" },
1037        { NULL }
1038};
1039
1040static char *imc_away_alias_find( GList *gcm, char *away )
1041{
1042        GList *m;
1043        int i, j;
1044       
1045        for( i = 0; *imc_away_alias_list[i]; i ++ )
1046        {
1047                for( j = 0; imc_away_alias_list[i][j]; j ++ )
1048                        if( g_strncasecmp( away, imc_away_alias_list[i][j], strlen( imc_away_alias_list[i][j] ) ) == 0 )
1049                                break;
1050               
1051                if( !imc_away_alias_list[i][j] )        /* If we reach the end, this row */
1052                        continue;                       /* is not what we want. Next!    */
1053               
1054                /* Now find an entry in this row which exists in gcm */
1055                for( j = 0; imc_away_alias_list[i][j]; j ++ )
1056                {
1057                        m = gcm;
1058                        while( m )
1059                        {
1060                                if( g_strcasecmp( imc_away_alias_list[i][j], m->data ) == 0 )
1061                                        return( imc_away_alias_list[i][j] );
1062                                m = m->next;
1063                        }
1064                }
1065        }
1066       
1067        return( NULL );
1068}
1069
1070void imc_add_allow( struct im_connection *ic, char *handle )
1071{
1072        if( g_slist_find_custom( ic->permit, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) == NULL )
1073        {
1074                ic->permit = g_slist_prepend( ic->permit, g_strdup( handle ) );
1075        }
1076       
1077        ic->acc->prpl->add_permit( ic, handle );
1078}
1079
1080void imc_rem_allow( struct im_connection *ic, char *handle )
1081{
1082        GSList *l;
1083       
1084        if( ( l = g_slist_find_custom( ic->permit, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) ) )
1085        {
1086                g_free( l->data );
1087                ic->permit = g_slist_delete_link( ic->permit, l );
1088        }
1089       
1090        ic->acc->prpl->rem_permit( ic, handle );
1091}
1092
1093void imc_add_block( struct im_connection *ic, char *handle )
1094{
1095        if( g_slist_find_custom( ic->deny, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) == NULL )
1096        {
1097                ic->deny = g_slist_prepend( ic->deny, g_strdup( handle ) );
1098        }
1099       
1100        ic->acc->prpl->add_deny( ic, handle );
1101}
1102
1103void imc_rem_block( struct im_connection *ic, char *handle )
1104{
1105        GSList *l;
1106       
1107        if( ( l = g_slist_find_custom( ic->deny, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) ) )
1108        {
1109                g_free( l->data );
1110                ic->deny = g_slist_delete_link( ic->deny, l );
1111        }
1112       
1113        ic->acc->prpl->rem_deny( ic, handle );
1114}
1115
1116void imcb_clean_handle( struct im_connection *ic, char *handle )
1117{
1118        /* Accepts a handle and does whatever is necessary to make it
1119           BitlBee-friendly. Currently this means removing everything
1120           outside 33-127 (ASCII printable excl spaces), @ (only one
1121           is allowed) and ! and : */
1122        char out[strlen(handle)+1];
1123        int s, d;
1124       
1125        s = d = 0;
1126        while( handle[s] )
1127        {
1128                if( handle[s] > ' ' && handle[s] != '!' && handle[s] != ':' &&
1129                    ( handle[s] & 0x80 ) == 0 )
1130                {
1131                        if( handle[s] == '@' )
1132                        {
1133                                /* See if we got an @ already? */
1134                                out[d] = 0;
1135                                if( strchr( out, '@' ) )
1136                                        continue;
1137                        }
1138                       
1139                        out[d++] = handle[s];
1140                }
1141                s ++;
1142        }
1143        out[d] = handle[s];
1144       
1145        strcpy( handle, out );
1146}
Note: See TracBrowser for help on using the repository browser.