source: protocols/nogaim.c @ d860a8d

Last change on this file since d860a8d was d860a8d, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-04-01T03:38:50Z

Restored "account" root command and restored enough stuff to be able to
send messages. Also started moving stuff out from nogaim.* into bee_* files.

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