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
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
[b7d3cc34]40GSList *connections;
41
[65e2ce1]42#ifdef WITH_PLUGINS
[7b23afd]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) {
[8ad90fb]50                log_message(LOGLVL_ERROR, "Can't find `%s', not loading (%s)\n", path, g_module_error());
[7b23afd]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}
[b7d3cc34]63
[65e2ce1]64void load_plugins(void)
65{
66        GDir *dir;
67        GError *error = NULL;
68
[4bfca70]69        dir = g_dir_open(global.conf->plugindir, 0, &error);
[65e2ce1]70
71        if (dir) {
72                const gchar *entry;
73                char *path;
74
75                while ((entry = g_dir_read_name(dir))) {
[4bfca70]76                        path = g_build_filename(global.conf->plugindir, entry, NULL);
[65e2ce1]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
[b7d3cc34]91
[7b23afd]92GList *protocols = NULL;
93 
94void register_protocol (struct prpl *p)
95{
[90cd6c4]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);
[7b23afd]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
[b7d3cc34]123void nogaim_init()
124{
[0da65d5]125        extern void msn_initmodule();
126        extern void oscar_initmodule();
127        extern void byahoo_initmodule();
128        extern void jabber_initmodule();
[7b23afd]129
[b7d3cc34]130#ifdef WITH_MSN
[0da65d5]131        msn_initmodule();
[b7d3cc34]132#endif
133
134#ifdef WITH_OSCAR
[0da65d5]135        oscar_initmodule();
[b7d3cc34]136#endif
137       
138#ifdef WITH_YAHOO
[0da65d5]139        byahoo_initmodule();
[b7d3cc34]140#endif
141       
142#ifdef WITH_JABBER
[0da65d5]143        jabber_initmodule();
[b7d3cc34]144#endif
[7b23afd]145
[65e2ce1]146#ifdef WITH_PLUGINS
147        load_plugins();
[b7d3cc34]148#endif
149}
150
151GSList *get_connections() { return connections; }
152
[84b045d]153struct im_connection *imcb_new( account_t *acc )
[b7d3cc34]154{
[0da65d5]155        struct im_connection *ic;
[b7d3cc34]156       
[0da65d5]157        ic = g_new0( struct im_connection, 1 );
[b7d3cc34]158       
[81e04e1]159        ic->bee = acc->bee;
[0da65d5]160        ic->acc = acc;
161        acc->ic = ic;
[b7d3cc34]162       
[0da65d5]163        connections = g_slist_append( connections, ic );
[b7d3cc34]164       
[0da65d5]165        return( ic );
[b7d3cc34]166}
167
[aef4828]168void imc_free( struct im_connection *ic )
[b7d3cc34]169{
170        account_t *a;
171       
172        /* Destroy the pointer to this connection from the account list */
[81e04e1]173        for( a = ic->bee->accounts; a; a = a->next )
[0da65d5]174                if( a->ic == ic )
[b7d3cc34]175                {
[0da65d5]176                        a->ic = NULL;
[b7d3cc34]177                        break;
178                }
179       
[0da65d5]180        connections = g_slist_remove( connections, ic );
181        g_free( ic );
[b7d3cc34]182}
183
[aef4828]184static void serv_got_crap( struct im_connection *ic, char *format, ... )
[b7d3cc34]185{
186        va_list params;
[e27661d]187        char *text;
[dfde8e0]188        account_t *a;
[b7d3cc34]189       
190        va_start( params, format );
[e27661d]191        text = g_strdup_vprintf( format, params );
[b7d3cc34]192        va_end( params );
193
[81e04e1]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" ) ) )
[e27661d]196                strip_html( text );
[b7d3cc34]197       
[dfde8e0]198        /* Try to find a different connection on the same protocol. */
[81e04e1]199        for( a = ic->bee->accounts; a; a = a->next )
[0da65d5]200                if( a->prpl == ic->acc->prpl && a->ic != ic )
[dfde8e0]201                        break;
202       
[e27661d]203        /* If we found one, include the screenname in the message. */
[dfde8e0]204        if( a )
[81e04e1]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 );
[dfde8e0]207        else
[81e04e1]208                irc_usermsg( ic->bee->ui_data, "%s - %s", ic->acc->prpl->name, text );
[7b07dc6]209       
[e27661d]210        g_free( text );
[b7d3cc34]211}
212
[84b045d]213void imcb_log( struct im_connection *ic, char *format, ... )
[aef4828]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
[84b045d]230void imcb_error( struct im_connection *ic, char *format, ... )
[aef4828]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
[ba9edaa]247static gboolean send_keepalive( gpointer d, gint fd, b_input_condition cond )
[b7d3cc34]248{
[0da65d5]249        struct im_connection *ic = d;
[b7d3cc34]250       
[0da65d5]251        if( ic->acc->prpl->keepalive )
252                ic->acc->prpl->keepalive( ic );
[b7d3cc34]253       
254        return TRUE;
255}
256
[84b045d]257void imcb_connected( struct im_connection *ic )
[b7d3cc34]258{
259        /* MSN servers sometimes redirect you to a different server and do
[84c1a0a]260           the whole login sequence again, so these "late" calls to this
[b7d3cc34]261           function should be handled correctly. (IOW, ignored) */
[0da65d5]262        if( ic->flags & OPT_LOGGED_IN )
[b7d3cc34]263                return;
264       
[84b045d]265        imcb_log( ic, "Logged in" );
[b7d3cc34]266       
[0da65d5]267        ic->keepalive = b_timeout_add( 60000, send_keepalive, ic );
268        ic->flags |= OPT_LOGGED_IN;
[b7d3cc34]269       
[58adb7e]270        /* Necessary to send initial presence status, even if we're not away. */
271        imc_away_send_update( ic );
[280e655]272       
273        /* Apparently we're connected successfully, so reset the
274           exponential backoff timer. */
275        ic->acc->auto_reconnect_delay = 0;
[3611717]276       
[10a96f4]277        /*
[3611717]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" ) )
[94acdd0]284                        chat_join( irc, c, NULL );
[3611717]285        }
[10a96f4]286        */
[b7d3cc34]287}
288
[ba9edaa]289gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond )
[b7d3cc34]290{
291        account_t *a = data;
292       
293        a->reconnect = 0;
[81e04e1]294        account_on( a->bee, a );
[b7d3cc34]295       
296        return( FALSE );        /* Only have to run the timeout once */
297}
298
299void cancel_auto_reconnect( account_t *a )
300{
[c98be00]301        b_event_remove( a->reconnect );
[b7d3cc34]302        a->reconnect = 0;
303}
304
[c2fb3809]305void imc_logout( struct im_connection *ic, int allow_reconnect )
[b7d3cc34]306{
[81e04e1]307        bee_t *bee = ic->bee;
[b7d3cc34]308        account_t *a;
[81e04e1]309        GSList *l;
[4230221]310        int delay;
[b7d3cc34]311       
[8d74291]312        /* Nested calls might happen sometimes, this is probably the best
313           place to catch them. */
[0da65d5]314        if( ic->flags & OPT_LOGGING_OUT )
[8d74291]315                return;
[66f783f]316        else
[0da65d5]317                ic->flags |= OPT_LOGGING_OUT;
[8d74291]318       
[84b045d]319        imcb_log( ic, "Signing off.." );
[fb62f81f]320       
[0da65d5]321        b_event_remove( ic->keepalive );
322        ic->keepalive = 0;
323        ic->acc->prpl->logout( ic );
324        b_event_remove( ic->inpa );
[b7d3cc34]325       
[c0c43fb]326        g_free( ic->away );
327        ic->away = NULL;
328       
[81e04e1]329        for( l = bee->users; l; l = l->next )
[b7d3cc34]330        {
[81e04e1]331                bee_user_t *bu = l->data;
332               
333                if( bu->ic == ic )
334                        bee_user_free( bee, ic, bu->handle );
[b7d3cc34]335        }
336       
[81e04e1]337        //query_del_by_conn( ic->irc, ic );
[b7d3cc34]338       
[81e04e1]339        for( a = bee->accounts; a; a = a->next )
[0da65d5]340                if( a->ic == ic )
[b7d3cc34]341                        break;
342       
343        if( !a )
344        {
345                /* Uhm... This is very sick. */
346        }
[81e04e1]347        else if( allow_reconnect && set_getbool( &bee->set, "auto_reconnect" ) &&
[4230221]348                 set_getbool( &a->set, "auto_reconnect" ) &&
349                 ( delay = account_reconnect_delay( a ) ) > 0 )
[b7d3cc34]350        {
[84b045d]351                imcb_log( ic, "Reconnecting in %d seconds..", delay );
[c98be00]352                a->reconnect = b_timeout_add( delay * 1000, auto_reconnect, a );
[b7d3cc34]353        }
354       
[aef4828]355        imc_free( ic );
[b7d3cc34]356}
357
[9143aeb]358void imcb_ask( struct im_connection *ic, char *msg, void *data,
359               query_callback doit, query_callback dont )
[b7d3cc34]360{
[81e04e1]361        //query_add( ic->irc, ic, msg, doit, dont, data );
[b7d3cc34]362}
363
[c6ca3ee]364void imcb_add_buddy( struct im_connection *ic, const char *handle, const char *group )
[b7d3cc34]365{
[81e04e1]366        bee_user_t *bu;
367        bee_t *bee = ic->bee;
[b7d3cc34]368       
[81e04e1]369        if( bee_user_by_handle( bee, ic, handle ) )
[b7d3cc34]370        {
[81e04e1]371                if( set_getbool( &bee->set, "debug" ) )
[84b045d]372                        imcb_log( ic, "User already exists, ignoring add request: %s", handle );
[b7d3cc34]373               
374                return;
375               
[f0cb961]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. */
[b7d3cc34]380        }
381       
[81e04e1]382        bu = bee_user_new( bee, ic, handle );
383        bu->group = g_strdup( group );
[b7d3cc34]384}
385
[1d39159]386void imcb_rename_buddy( struct im_connection *ic, const char *handle, const char *fullname )
[b7d3cc34]387{
[1d39159]388        bee_t *bee = ic->bee;
389        bee_user_t *bu = bee_user_by_handle( bee, ic, handle );
[b7d3cc34]390       
[1d39159]391        if( !bu || !fullname ) return;
[b7d3cc34]392       
[17a6ee9]393        if( !bu->fullname || strcmp( bu->fullname, fullname ) != 0 )
[b7d3cc34]394        {
[1d39159]395                g_free( bu->fullname );
396                bu->fullname = g_strdup( fullname );
[b7d3cc34]397               
[1d39159]398                if( bee->ui->user_fullname )
399                        bee->ui->user_fullname( bee, bu );
[b7d3cc34]400        }
401}
402
[c6ca3ee]403void imcb_remove_buddy( struct im_connection *ic, const char *handle, char *group )
[998b103]404{
[81e04e1]405        bee_user_free( ic->bee, ic, handle );
[998b103]406}
407
[d06eabf]408/* Mainly meant for ICQ (and now also for Jabber conferences) to allow IM
409   modules to suggest a nickname for a handle. */
[fb00989]410void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick )
[d06eabf]411{
[81e04e1]412#if 0
[d06eabf]413        user_t *u = user_findhandle( ic, handle );
[43d8cc5]414        char newnick[MAX_NICK_LENGTH+1], *orig_nick;
[d06eabf]415       
[e0e2a71]416        if( u && !u->online && !nick_saved( ic->acc, handle ) )
[d06eabf]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               
[e0e2a71]422                strncpy( newnick, nick, MAX_NICK_LENGTH );
423                newnick[MAX_NICK_LENGTH] = 0;
[d06eabf]424               
425                /* Some processing to make sure this string is a valid IRC nickname. */
426                nick_strip( newnick );
[81e04e1]427                if( set_getbool( &ic->bee->set, "lcnicks" ) )
[d06eabf]428                        nick_lc( newnick );
429               
[1962ac1]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                }
[d06eabf]443        }
[81e04e1]444#endif
[d06eabf]445}
[b7d3cc34]446
447
[fa295e36]448struct imcb_ask_cb_data
[7bf0f5f0]449{
[0da65d5]450        struct im_connection *ic;
[7bf0f5f0]451        char *handle;
452};
453
[fb117aee]454#if 0
[fa295e36]455static void imcb_ask_auth_cb_no( void *data )
[7bf0f5f0]456{
[fa295e36]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}
[fb117aee]474#endif
[fa295e36]475
476void imcb_ask_auth( struct im_connection *ic, const char *handle, const char *realname )
477{
[81e04e1]478#if 0
[fa295e36]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 );
[81e04e1]493#endif
[fa295e36]494}
495
496
[fb117aee]497#if 0
[fa295e36]498static void imcb_ask_add_cb_no( void *data )
499{
500        g_free( ((struct imcb_ask_cb_data*)data)->handle );
[7bf0f5f0]501        g_free( data );
502}
503
[fa295e36]504static void imcb_ask_add_cb_yes( void *data )
[7bf0f5f0]505{
[fa295e36]506        struct imcb_ask_cb_data *cbd = data;
[7bf0f5f0]507       
[fa295e36]508        cbd->ic->acc->prpl->add_buddy( cbd->ic, cbd->handle, NULL );
[9143aeb]509       
[fa295e36]510        return imcb_ask_add_cb_no( data );
[7bf0f5f0]511}
[fb117aee]512#endif
[7bf0f5f0]513
[fa295e36]514void imcb_ask_add( struct im_connection *ic, const char *handle, const char *realname )
[b7d3cc34]515{
[81e04e1]516#if 0
[fa295e36]517        struct imcb_ask_cb_data *data = g_new0( struct imcb_ask_cb_data, 1 );
[7bf0f5f0]518        char *s;
519       
520        /* TODO: Make a setting for this! */
[0da65d5]521        if( user_findhandle( ic, handle ) != NULL )
[7bf0f5f0]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       
[0da65d5]526        data->ic = ic;
[7bf0f5f0]527        data->handle = g_strdup( handle );
[fa295e36]528        query_add( ic->irc, ic, s, imcb_ask_add_cb_yes, imcb_ask_add_cb_no, data );
[81e04e1]529#endif
[b7d3cc34]530}
531
[52744f8]532void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags )
[b7d3cc34]533{
[81e04e1]534#if 0
[b7d3cc34]535        user_t *u;
536       
[81e04e1]537        if( !set_getbool( &ic->bee->set, "typing_notice" ) )
[b7d3cc34]538                return;
539       
[9624fdf]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 );
[e7f46c5]546        }
[81e04e1]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 );
[b7d3cc34]553}
554
[94acdd0]555struct groupchat *imcb_chat_new( struct im_connection *ic, const char *handle )
[83ba3e5]556{
[81e04e1]557#if 0
[83ba3e5]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       
[81e04e1]575        if( set_getbool( &ic->bee->set, "debug" ) )
[83ba3e5]576                imcb_log( ic, "Creating new conversation: (id=%p,handle=%s)", c, handle );
577       
578        return c;
[81e04e1]579#endif
[fb117aee]580        return NULL;
[83ba3e5]581}
582
[e35d1a1]583void imcb_chat_free( struct groupchat *c )
[b7d3cc34]584{
[81e04e1]585#if 0
[0da65d5]586        struct im_connection *ic = c->ic;
[e35d1a1]587        struct groupchat *l;
[b7d3cc34]588        GList *ir;
589       
[81e04e1]590        if( set_getbool( &ic->bee->set, "debug" ) )
[56f260a]591                imcb_log( ic, "You were removed from conversation %p", c );
[b7d3cc34]592       
593        if( c )
594        {
595                if( c->joined )
596                {
597                        user_t *u, *r;
598                       
[0da65d5]599                        r = user_find( ic->irc, ic->irc->mynick );
600                        irc_privmsg( ic->irc, r, "PRIVMSG", c->channel, "", "Cleaning up channel, bye!" );
[b7d3cc34]601                       
[0da65d5]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 ); */
[b7d3cc34]605                }
606               
[e35d1a1]607                /* Find the previous chat in the linked list. */
608                for( l = ic->groupchats; l && l->next != c; l = l->next );
609               
[b7d3cc34]610                if( l )
611                        l->next = c->next;
612                else
[e35d1a1]613                        ic->groupchats = c->next;
[b7d3cc34]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 );
[83ba3e5]620                g_free( c->topic );
[b7d3cc34]621                g_free( c );
622        }
[81e04e1]623#endif
[b7d3cc34]624}
625
[c6ca3ee]626void imcb_chat_msg( struct groupchat *c, const char *who, char *msg, uint32_t flags, time_t sent_at )
[b7d3cc34]627{
[81e04e1]628#if 0
[0da65d5]629        struct im_connection *ic = c->ic;
[d444c09]630        char *wrapped;
[b7d3cc34]631        user_t *u;
632       
633        /* Gaim sends own messages through this too. IRC doesn't want this, so kill them */
[c2fb3809]634        if( g_strcasecmp( who, ic->acc->user ) == 0 )
[b7d3cc34]635                return;
636       
[0da65d5]637        u = user_findhandle( ic, who );
[b7d3cc34]638       
[81e04e1]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" ) ) )
[b7d3cc34]641                strip_html( msg );
642       
[d444c09]643        wrapped = word_wrap( msg, 425 );
[b7d3cc34]644        if( c && u )
[d444c09]645        {
646                irc_privmsg( ic->irc, u, "PRIVMSG", c->channel, "", wrapped );
647        }
[b7d3cc34]648        else
[d444c09]649        {
[56f260a]650                imcb_log( ic, "Message from/to conversation %s@%p (unknown conv/user): %s", who, c, wrapped );
[d444c09]651        }
652        g_free( wrapped );
[81e04e1]653#endif
[b7d3cc34]654}
655
[31e5846]656void imcb_chat_log( struct groupchat *c, char *format, ... )
657{
[81e04e1]658#if 0
[31e5846]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 );
[81e04e1]673#endif
[31e5846]674}
675
[ef5c185]676void imcb_chat_topic( struct groupchat *c, char *who, char *topic, time_t set_at )
[50e1776]677{
[81e04e1]678#if 0
[50e1776]679        struct im_connection *ic = c->ic;
680        user_t *u = NULL;
681       
682        if( who == NULL)
[ef5c185]683                u = user_find( ic->irc, ic->irc->mynick );
[50e1776]684        else if( g_strcasecmp( who, ic->acc->user ) == 0 )
[ef5c185]685                u = user_find( ic->irc, ic->irc->nick );
[50e1776]686        else
687                u = user_findhandle( ic, who );
688       
[81e04e1]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" ) ) )
[50e1776]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 );
[81e04e1]698#endif
[50e1776]699}
700
[c6ca3ee]701void imcb_chat_add_buddy( struct groupchat *b, const char *handle )
[b7d3cc34]702{
[81e04e1]703#if 0
[0da65d5]704        user_t *u = user_findhandle( b->ic, handle );
[b7d3cc34]705        int me = 0;
706       
[81e04e1]707        if( set_getbool( &b->ic->bee->set, "debug" ) )
[56f260a]708                imcb_log( b->ic, "User %s added to conversation %p", handle, b );
[b7d3cc34]709       
710        /* It might be yourself! */
[c2fb3809]711        if( b->ic->acc->prpl->handle_cmp( handle, b->ic->acc->user ) == 0 )
[b7d3cc34]712        {
[0da65d5]713                u = user_find( b->ic->irc, b->ic->irc->nick );
[b7d3cc34]714                if( !b->joined )
[0da65d5]715                        irc_join( b->ic->irc, u, b->channel );
[b7d3cc34]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        {
[f0cb961]723                imcb_add_buddy( b->ic, handle, NULL );
[0da65d5]724                u = user_findhandle( b->ic, handle );
[b7d3cc34]725        }
726       
727        /* Add the handle to the room userlist, if it's not 'me' */
728        if( !me )
729        {
730                if( b->joined )
[0da65d5]731                        irc_join( b->ic->irc, u, b->channel );
[b7d3cc34]732                b->in_room = g_list_append( b->in_room, g_strdup( handle ) );
733        }
[81e04e1]734#endif
[b7d3cc34]735}
736
[2d317bb]737/* This function is one BIG hack... :-( EREWRITE */
[c6ca3ee]738void imcb_chat_remove_buddy( struct groupchat *b, const char *handle, const char *reason )
[b7d3cc34]739{
[81e04e1]740#if 0
[b7d3cc34]741        user_t *u;
742        int me = 0;
743       
[81e04e1]744        if( set_getbool( &b->ic->bee->set, "debug" ) )
[56f260a]745                imcb_log( b->ic, "User %s removed from conversation %p (%s)", handle, b, reason ? reason : "" );
[b7d3cc34]746       
747        /* It might be yourself! */
[c2fb3809]748        if( g_strcasecmp( handle, b->ic->acc->user ) == 0 )
[b7d3cc34]749        {
[2d317bb]750                if( b->joined == 0 )
751                        return;
752               
[0da65d5]753                u = user_find( b->ic->irc, b->ic->irc->nick );
[b7d3cc34]754                b->joined = 0;
755                me = 1;
756        }
757        else
758        {
[0da65d5]759                u = user_findhandle( b->ic, handle );
[b7d3cc34]760        }
761       
[2d317bb]762        if( me || ( remove_chat_buddy_silent( b, handle ) && b->joined && u ) )
763                irc_part( b->ic->irc, u, b->channel );
[81e04e1]764#endif
[b7d3cc34]765}
766
[fb117aee]767#if 0
[764b163d]768static int remove_chat_buddy_silent( struct groupchat *b, const char *handle )
[b7d3cc34]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       
[81e04e1]786        return 0;
[b7d3cc34]787}
[fb117aee]788#endif
[b7d3cc34]789
790
791/* Misc. BitlBee stuff which shouldn't really be here */
[81e04e1]792#if 0
[5c9512f]793char *set_eval_away_devoice( set_t *set, char *value )
[b7d3cc34]794{
[5c9512f]795        irc_t *irc = set->data;
[b7d3cc34]796        int st;
797       
[7125cb3]798        if( !is_bool( value ) )
799                return SET_INVALID;
[b7d3cc34]800       
[7125cb3]801        st = bool2int( value );
[b7d3cc34]802       
803        /* Horror.... */
804       
[10a96f4]805        if( st != set_getbool( &irc->b->set, "away_devoice" ) )
[b7d3cc34]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                {
[0da65d5]820                        if( u->ic && u->online && !u->away )
[b7d3cc34]821                        {
822                                if( ( strlen( list ) + strlen( u->nick ) ) >= 79 )
823                                {
824                                        for( i = 0; i < count; v[i++] = 'v' ); v[i] = 0;
[2087159]825                                        irc_write( irc, ":%s MODE %s %c%s%s",
826                                                   irc->myhost,
[b7d3cc34]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;
[2087159]841                irc_write( irc, ":%s MODE %s %c%s%s", irc->myhost,
[b7d3cc34]842                                                            irc->channel, pm, v, list );
843        }
844       
[7125cb3]845        return value;
[b7d3cc34]846}
[81e04e1]847#endif
[226fce1]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
[84b045d]854int imc_chat_msg( struct groupchat *c, char *msg, int flags )
[b7d3cc34]855{
[e27661d]856        char *buf = NULL;
[b7d3cc34]857       
[6bbb939]858        if( ( c->ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )
[e27661d]859        {
860                buf = escape_html( msg );
[b7d3cc34]861                msg = buf;
862        }
863       
[f6c963b]864        c->ic->acc->prpl->chat_msg( c, msg, flags );
[e27661d]865        g_free( buf );
866       
[0da65d5]867        return 1;
[b7d3cc34]868}
[226fce1]869
[34fbbf9]870static char *imc_away_state_find( GList *gcm, char *away, char **message );
[226fce1]871
[58adb7e]872int imc_away_send_update( struct im_connection *ic )
[226fce1]873{
[3e1ef92c]874        char *away, *msg = NULL;
[226fce1]875       
[58adb7e]876        away = set_getstr( &ic->acc->set, "away" ) ?
[81e04e1]877             : set_getstr( &ic->bee->set, "away" );
[34fbbf9]878        if( away && *away )
[226fce1]879        {
[34fbbf9]880                GList *m = ic->acc->prpl->away_states( ic );
[58adb7e]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" ) ?
[81e04e1]888                    : set_getstr( &ic->bee->set, "status" );
[226fce1]889        }
890       
[58adb7e]891        ic->acc->prpl->set_away( ic, away, msg );
[226fce1]892       
[34fbbf9]893        return 1;
[226fce1]894}
895
[84b045d]896static char *imc_away_alias_list[8][5] =
[226fce1]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
[34fbbf9]908static char *imc_away_state_find( GList *gcm, char *away, char **message )
[226fce1]909{
910        GList *m;
911        int i, j;
912       
[34fbbf9]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       
[84b045d]925        for( i = 0; *imc_away_alias_list[i]; i ++ )
[226fce1]926        {
[34fbbf9]927                int keep_message;
928               
[84b045d]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 )
[34fbbf9]931                        {
932                                keep_message = strlen( away ) != strlen( imc_away_alias_list[i][j] );
[226fce1]933                                break;
[34fbbf9]934                        }
[226fce1]935               
[84b045d]936                if( !imc_away_alias_list[i][j] )        /* If we reach the end, this row */
[226fce1]937                        continue;                       /* is not what we want. Next!    */
938               
939                /* Now find an entry in this row which exists in gcm */
[84b045d]940                for( j = 0; imc_away_alias_list[i][j]; j ++ )
[226fce1]941                {
[34fbbf9]942                        for( m = gcm; m; m = m->next )
[84b045d]943                                if( g_strcasecmp( imc_away_alias_list[i][j], m->data ) == 0 )
[34fbbf9]944                                {
945                                        if( !keep_message )
946                                                *message = NULL;
947                                       
948                                        return imc_away_alias_list[i][j];
949                                }
[226fce1]950                }
[34fbbf9]951               
952                /* No need to look further, apparently this state doesn't
953                   have any good alias for this protocol. */
954                break;
[226fce1]955        }
956       
[34fbbf9]957        return NULL;
[226fce1]958}
[da3b536]959
[84b045d]960void imc_add_allow( struct im_connection *ic, char *handle )
[da3b536]961{
[0da65d5]962        if( g_slist_find_custom( ic->permit, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) == NULL )
[da3b536]963        {
[0da65d5]964                ic->permit = g_slist_prepend( ic->permit, g_strdup( handle ) );
[da3b536]965        }
966       
[0da65d5]967        ic->acc->prpl->add_permit( ic, handle );
[da3b536]968}
969
[84b045d]970void imc_rem_allow( struct im_connection *ic, char *handle )
[da3b536]971{
972        GSList *l;
973       
[0da65d5]974        if( ( l = g_slist_find_custom( ic->permit, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) ) )
[da3b536]975        {
976                g_free( l->data );
[0da65d5]977                ic->permit = g_slist_delete_link( ic->permit, l );
[da3b536]978        }
979       
[0da65d5]980        ic->acc->prpl->rem_permit( ic, handle );
[da3b536]981}
982
[84b045d]983void imc_add_block( struct im_connection *ic, char *handle )
[da3b536]984{
[0da65d5]985        if( g_slist_find_custom( ic->deny, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) == NULL )
[da3b536]986        {
[0da65d5]987                ic->deny = g_slist_prepend( ic->deny, g_strdup( handle ) );
[da3b536]988        }
989       
[0da65d5]990        ic->acc->prpl->add_deny( ic, handle );
[da3b536]991}
992
[84b045d]993void imc_rem_block( struct im_connection *ic, char *handle )
[da3b536]994{
995        GSList *l;
996       
[0da65d5]997        if( ( l = g_slist_find_custom( ic->deny, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) ) )
[da3b536]998        {
999                g_free( l->data );
[0da65d5]1000                ic->deny = g_slist_delete_link( ic->deny, l );
[da3b536]1001        }
1002       
[0da65d5]1003        ic->acc->prpl->rem_deny( ic, handle );
[da3b536]1004}
[85023c6]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.