source: irc_im.c @ 03f3828

Last change on this file since 03f3828 was 03f3828, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-24T14:06:22Z

Adding protocol-specific chatroom settings. First one to use this: AIM
chatrooms to use exchange numbers other than 4.

  • Property mode set to 100644
File size: 22.0 KB
RevLine 
[81e04e1]1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* Some glue to put the IRC and the IM stuff together.                  */
8
9/*
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License with
21  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23  Suite 330, Boston, MA  02111-1307  USA
24*/
25
26#include "bitlbee.h"
[17a6ee9]27#include "dcc.h"
[d860a8d]28
[e4816ea]29/* IM->IRC callbacks: Simple IM/buddy-related stuff. */
[d860a8d]30
[81e04e1]31static const struct irc_user_funcs irc_user_im_funcs;
32
[5c7b45c]33static void bee_irc_imc_connected( struct im_connection *ic )
34{
35        irc_t *irc = (irc_t*) ic->bee->ui_data;
36       
37        irc_channel_auto_joins( irc, ic->acc );
38}
39
40static void bee_irc_imc_disconnected( struct im_connection *ic )
41{
42        /* Maybe try to send /QUITs here instead of later on. */
43}
44
[81e04e1]45static gboolean bee_irc_user_new( bee_t *bee, bee_user_t *bu )
46{
47        irc_user_t *iu;
[92c8d41]48        irc_t *irc = (irc_t*) bee->ui_data;
[81e04e1]49        char nick[MAX_NICK_LENGTH+1], *s;
50       
51        memset( nick, 0, MAX_NICK_LENGTH + 1 );
[b1f818b]52        strcpy( nick, nick_get( bu ) );
[81e04e1]53       
[92c8d41]54        bu->ui_data = iu = irc_user_new( irc, nick );
[d860a8d]55        iu->bu = bu;
[81e04e1]56       
57        if( ( s = strchr( bu->handle, '@' ) ) )
58        {
59                iu->host = g_strdup( s + 1 );
60                iu->user = g_strndup( bu->handle, s - bu->handle );
61        }
62        else if( bu->ic->acc->server )
63        {
64                iu->host = g_strdup( bu->ic->acc->server );
65                iu->user = g_strdup( bu->handle );
66               
67                /* s/ /_/ ... important for AOL screennames */
68                for( s = iu->user; *s; s ++ )
69                        if( *s == ' ' )
70                                *s = '_';
71        }
72        else
73        {
74                iu->host = g_strdup( bu->ic->acc->prpl->name );
75                iu->user = g_strdup( bu->handle );
76        }
77       
[ad404ab]78        if( bu->flags & BEE_USER_LOCAL )
79        {
80                char *s = set_getstr( &bee->set, "handle_unknown" );
81               
82                if( strcmp( s, "add_private" ) == 0 )
[92c8d41]83                        iu->last_channel = NULL;
[ad404ab]84                else if( strcmp( s, "add_channel" ) == 0 )
[92c8d41]85                        iu->last_channel = irc->default_channel;
[ad404ab]86        }
87       
[81e04e1]88        iu->f = &irc_user_im_funcs;
89       
90        return TRUE;
91}
92
[d860a8d]93static gboolean bee_irc_user_free( bee_t *bee, bee_user_t *bu )
94{
[eabc9d2]95        return irc_user_free( bee->ui_data, (irc_user_t *) bu->ui_data );
[d860a8d]96}
[81e04e1]97
[d860a8d]98static gboolean bee_irc_user_status( bee_t *bee, bee_user_t *bu, bee_user_t *old )
99{
[231b08b]100        irc_t *irc = bee->ui_data;
[003a12b]101        irc_user_t *iu = bu->ui_data;
[231b08b]102       
[eb50495]103        /* Do this outside the if below since away state can change without
104           the online state changing. */
105        iu->flags &= ~IRC_USER_AWAY;
106        if( bu->flags & BEE_USER_AWAY || !( bu->flags & BEE_USER_ONLINE ) )
107                iu->flags |= IRC_USER_AWAY;
108       
[231b08b]109        if( ( bu->flags & BEE_USER_ONLINE ) != ( old->flags & BEE_USER_ONLINE ) )
110        {
111                if( bu->flags & BEE_USER_ONLINE )
[003a12b]112                {
113                        if( g_hash_table_lookup( irc->watches, iu->key ) )
114                                irc_send_num( irc, 600, "%s %s %s %d :%s", iu->nick, iu->user,
115                                              iu->host, (int) time( NULL ), "logged online" );
116                }
[231b08b]117                else
[003a12b]118                {
119                        if( g_hash_table_lookup( irc->watches, iu->key ) )
120                                irc_send_num( irc, 601, "%s %s %s %d :%s", iu->nick, iu->user,
121                                              iu->host, (int) time( NULL ), "logged offline" );
[0bd948e]122                       
123                        /* Send a QUIT since those will also show up in any
124                           query windows the user may have, plus it's only
125                           one QUIT instead of possibly many (in case of
126                           multiple control chans). If there's a channel that
127                           shows offline people, a JOIN will follow. */
128                        if( set_getbool( &bee->set, "offline_user_quits" ) )
129                                irc_user_quit( iu, "Leaving..." );
[003a12b]130                }
[231b08b]131        }
132       
[1c8e5f7]133        /* Reset this one since the info may have changed. */
134        iu->away_reply_timeout = 0;
135       
[13c1a9f]136        bee_irc_channel_update( irc, NULL, iu );
137       
[d860a8d]138        return TRUE;
139}
[81e04e1]140
[13c1a9f]141void bee_irc_channel_update( irc_t *irc, irc_channel_t *ic, irc_user_t *iu )
142{
143        struct irc_control_channel *icc;
144        GSList *l;
[94d5da9c]145        gboolean match = FALSE;
[13c1a9f]146       
147        if( ic == NULL )
148        {
149                for( l = irc->channels; l; l = l->next )
150                {
151                        ic = l->data;
152                        /* TODO: Just add a type flag or so.. */
[9052bc1]153                        if( ic->f == irc->default_channel->f &&
154                            ( ic->flags & IRC_CHANNEL_JOINED ) )
[13c1a9f]155                                bee_irc_channel_update( irc, ic, iu );
156                }
157                return;
158        }
159        if( iu == NULL )
160        {
161                for( l = irc->users; l; l = l->next )
162                {
163                        iu = l->data;
164                        if( iu->bu )
165                                bee_irc_channel_update( irc, ic, l->data );
166                }
167                return;
168        }
169       
170        icc = ic->data;
171       
[94d5da9c]172        if( icc->type == IRC_CC_TYPE_DEFAULT )
173                match = TRUE;
[13c1a9f]174        else if( icc->type == IRC_CC_TYPE_GROUP )
[94d5da9c]175                match = iu->bu->group == icc->group;
[a067771]176        else if( icc->type == IRC_CC_TYPE_ACCOUNT )
[94d5da9c]177                match = iu->bu->ic->acc == icc->account;
[7a6ba50]178        else if( icc->type == IRC_CC_TYPE_PROTOCOL )
[94d5da9c]179                match = iu->bu->ic->acc->prpl == icc->protocol;
[13c1a9f]180       
[94d5da9c]181        if( !match )
[13c1a9f]182        {
[006a84f]183                irc_channel_del_user( ic, iu, IRC_CDU_PART, NULL );
[13c1a9f]184        }
185        else
186        {
[94d5da9c]187                int mode = 0;
[13c1a9f]188               
[94d5da9c]189                if( !( iu->bu->flags & BEE_USER_ONLINE ) )
190                        mode = icc->modes[0];
191                else if( iu->bu->flags & BEE_USER_AWAY )
192                        mode = icc->modes[1];
[0e8b3e8]193                else
[94d5da9c]194                        mode = icc->modes[2];
195               
196                if( !mode )
197                        irc_channel_del_user( ic, iu, IRC_CDU_PART, NULL );
198                else
199                {
200                        irc_channel_add_user( ic, iu );
201                        irc_channel_user_set_mode( ic, iu, mode );
202                }
[13c1a9f]203        }
204}
205
[f012a9f]206static gboolean bee_irc_user_msg( bee_t *bee, bee_user_t *bu, const char *msg, time_t sent_at )
207{
208        irc_t *irc = bee->ui_data;
209        irc_user_t *iu = (irc_user_t *) bu->ui_data;
210        char *dst, *prefix = NULL;
[21c87a7]211        char *wrapped, *ts = NULL;
212       
213        if( sent_at > 0 && set_getbool( &irc->b->set, "display_timestamps" ) )
214                ts = irc_format_timestamp( irc, sent_at );
[f012a9f]215       
[92c8d41]216        if( iu->last_channel )
[f012a9f]217        {
[92c8d41]218                dst = iu->last_channel->name;
219                prefix = g_strdup_printf( "%s%s%s", irc->user->nick, set_getstr( &bee->set, "to_char" ), ts ? : "" );
[f012a9f]220        }
221        else
222        {
[92c8d41]223                dst = irc->user->nick;
224                prefix = ts;
225                ts = NULL;
[f012a9f]226        }
227       
228        wrapped = word_wrap( msg, 425 );
229        irc_send_msg( iu, "PRIVMSG", dst, wrapped, prefix );
230       
231        g_free( wrapped );
232        g_free( prefix );
[21c87a7]233        g_free( ts );
[f012a9f]234       
235        return TRUE;
236}
237
[573dab0]238static gboolean bee_irc_user_typing( bee_t *bee, bee_user_t *bu, uint32_t flags )
239{
240        irc_t *irc = (irc_t *) bee->ui_data;
241       
242        if( set_getbool( &bee->set, "typing_notice" ) )
243                irc_send_msg_f( (irc_user_t *) bu->ui_data, "PRIVMSG", irc->user->nick,
244                                "\001TYPING %d\001", ( flags >> 8 ) & 3 );
245        else
246                return FALSE;
247       
248        return TRUE;
249}
250
[badd148]251static gboolean bee_irc_user_nick_update( irc_user_t *iu );
[6ef9065]252
[1d39159]253static gboolean bee_irc_user_fullname( bee_t *bee, bee_user_t *bu )
254{
255        irc_user_t *iu = (irc_user_t *) bu->ui_data;
256        irc_t *irc = (irc_t *) bee->ui_data;
257        char *s;
258       
259        if( iu->fullname != iu->nick )
260                g_free( iu->fullname );
261        iu->fullname = g_strdup( bu->fullname );
262       
263        /* Strip newlines (unlikely, but IRC-unfriendly so they must go)
264           TODO(wilmer): Do the same with away msgs again! */
265        for( s = iu->fullname; *s; s ++ )
266                if( isspace( *s ) ) *s = ' ';
267       
268        if( ( bu->ic->flags & OPT_LOGGED_IN ) && set_getbool( &bee->set, "display_namechanges" ) )
269        {
270                char *msg = g_strdup_printf( "<< \002BitlBee\002 - Changed name to `%s' >>", iu->fullname );
271                irc_send_msg( iu, "NOTICE", irc->user->nick, msg, NULL );
272        }
273       
[badd148]274        bee_irc_user_nick_update( iu );
[1d39159]275       
276        return TRUE;
277}
278
[6ef9065]279static gboolean bee_irc_user_nick_hint( bee_t *bee, bee_user_t *bu, const char *hint )
280{
[badd148]281        bee_irc_user_nick_update( (irc_user_t*) bu->ui_data );
282       
283        return TRUE;
284}
285
286static gboolean bee_irc_user_group( bee_t *bee, bee_user_t *bu )
287{
288        irc_user_t *iu = (irc_user_t *) bu->ui_data;
289        irc_t *irc = (irc_t *) bee->ui_data;
290       
291        bee_irc_channel_update( irc, NULL, iu );
292        bee_irc_user_nick_update( iu );
293       
294        return TRUE;
295}
296
297static gboolean bee_irc_user_nick_update( irc_user_t *iu )
298{
299        bee_user_t *bu = iu->bu;
300        char *newnick;
[6ef9065]301       
302        if( bu->flags & BEE_USER_ONLINE )
303                /* Ignore if the user is visible already. */
304                return TRUE;
305       
[b1f818b]306        if( nick_saved( bu ) )
[6ef9065]307                /* The user already assigned a nickname to this person. */
308                return TRUE;
309       
[badd148]310        newnick = nick_get( bu );
[6ef9065]311       
312        if( strcmp( iu->nick, newnick ) != 0 )
313        {
[b1f818b]314                nick_dedupe( bu, newnick );
[6ef9065]315                irc_user_set_nick( iu, newnick );
316        }
317       
318        return TRUE;
319}
320
[e4816ea]321/* IRC->IM calls */
322
[619dd18]323static gboolean bee_irc_user_privmsg_cb( gpointer data, gint fd, b_input_condition cond );
324
[e4816ea]325static gboolean bee_irc_user_privmsg( irc_user_t *iu, const char *msg )
326{
[1c8e5f7]327        const char *away;
328       
[619dd18]329        if( iu->bu == NULL )
[e4816ea]330                return FALSE;
[1c8e5f7]331       
332        if( ( away = irc_user_get_away( iu ) ) &&
333            time( NULL ) >= iu->away_reply_timeout )
334        {
335                irc_send_num( iu->irc, 301, "%s :%s", iu->nick, away );
336                iu->away_reply_timeout = time( NULL ) +
337                        set_getint( &iu->irc->b->set, "away_reply_timeout" );
338        }
339       
340        if( set_getbool( &iu->irc->b->set, "paste_buffer" ) )
[619dd18]341        {
342                int delay;
343               
344                if( iu->pastebuf == NULL )
345                        iu->pastebuf = g_string_new( msg );
346                else
347                {
348                        b_event_remove( iu->pastebuf_timer );
349                        g_string_append_printf( iu->pastebuf, "\n%s", msg );
350                }
351               
352                if( ( delay = set_getint( &iu->irc->b->set, "paste_buffer_delay" ) ) <= 5 )
353                        delay *= 1000;
354               
355                iu->pastebuf_timer = b_timeout_add( delay, bee_irc_user_privmsg_cb, iu );
356               
357                return TRUE;
358        }
359        else
360                return bee_user_msg( iu->irc->b, iu->bu, msg, 0 );
361}
362
363static gboolean bee_irc_user_privmsg_cb( gpointer data, gint fd, b_input_condition cond )
364{
365        irc_user_t *iu = data;
366       
367        bee_user_msg( iu->irc->b, iu->bu, iu->pastebuf->str, 0 );
368       
369        g_string_free( iu->pastebuf, TRUE );
370        iu->pastebuf = 0;
371        iu->pastebuf_timer = 0;
372       
373        return FALSE;
[e4816ea]374}
375
376static gboolean bee_irc_user_ctcp( irc_user_t *iu, char *const *ctcp )
377{
378        if( ctcp[1] && g_strcasecmp( ctcp[0], "DCC" ) == 0
379                    && g_strcasecmp( ctcp[1], "SEND" ) == 0 )
380        {
381                if( iu->bu && iu->bu->ic && iu->bu->ic->acc->prpl->transfer_request )
382                {
383                        file_transfer_t *ft = dcc_request( iu->bu->ic, ctcp );
384                        if ( ft )
385                                iu->bu->ic->acc->prpl->transfer_request( iu->bu->ic, ft, iu->bu->handle );
386                       
387                        return TRUE;
388                }
389        }
390        else if( g_strcasecmp( ctcp[0], "TYPING" ) == 0 )
391        {
392                if( iu->bu && iu->bu->ic && iu->bu->ic->acc->prpl->send_typing && ctcp[1] )
393                {
394                        int st = ctcp[1][0];
395                        if( st >= '0' && st <= '2' )
396                        {
397                                st <<= 8;
398                                iu->bu->ic->acc->prpl->send_typing( iu->bu->ic, iu->bu->handle, st );
399                        }
400                       
401                        return TRUE;
402                }
403        }
404       
405        return FALSE;
406}
407
408static const struct irc_user_funcs irc_user_im_funcs = {
409        bee_irc_user_privmsg,
410        bee_irc_user_ctcp,
411};
412
[aea8b68]413
[e4816ea]414/* IM->IRC: Groupchats */
[5a75d15]415const struct irc_channel_funcs irc_channel_im_chat_funcs;
[a87754b]416
417static gboolean bee_irc_chat_new( bee_t *bee, struct groupchat *c )
[aea8b68]418{
419        irc_t *irc = bee->ui_data;
420        irc_channel_t *ic;
421        char *topic;
[eb37735]422        GSList *l;
[aea8b68]423        int i;
424       
[eb37735]425        /* Try to find a channel that expects to receive a groupchat.
[52a2521]426           This flag is set earlier in our current call trace. */
[eb37735]427        for( l = irc->channels; l; l = l->next )
428        {
429                ic = l->data;
430                if( ic->flags & IRC_CHANNEL_CHAT_PICKME )
431                        break;
432        }
433       
434        /* If we found none, just generate some stupid name. */
435        if( l == NULL ) for( i = 0; i <= 999; i ++ )
[aea8b68]436        {
437                char name[16];
[5a75d15]438                sprintf( name, "#chat_%03d", i );
[aea8b68]439                if( ( ic = irc_channel_new( irc, name ) ) )
440                        break;
441        }
442       
443        if( ic == NULL )
444                return FALSE;
445       
446        c->ui_data = ic;
447        ic->data = c;
448       
449        topic = g_strdup_printf( "BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!", c->title );
450        irc_channel_set_topic( ic, topic, irc->root );
451        g_free( topic );
452       
453        return TRUE;
454}
455
[a87754b]456static gboolean bee_irc_chat_free( bee_t *bee, struct groupchat *c )
[aea8b68]457{
458        irc_channel_t *ic = c->ui_data;
459       
[b1af3e8]460        if( ic == NULL )
461                return FALSE;
462       
[aea8b68]463        if( ic->flags & IRC_CHANNEL_JOINED )
464                irc_channel_printf( ic, "Cleaning up channel, bye!" );
465       
[5a75d15]466        ic->data = NULL;
[006a84f]467        irc_channel_del_user( ic, ic->irc->user, IRC_CDU_KICK, "Chatroom closed by server" );
[aea8b68]468       
469        return TRUE;
470}
471
[a87754b]472static gboolean bee_irc_chat_log( bee_t *bee, struct groupchat *c, const char *text )
[aea8b68]473{
[27e2c66]474        irc_channel_t *ic = c->ui_data;
475       
[b1af3e8]476        if( ic == NULL )
477                return FALSE;
478       
[27e2c66]479        irc_channel_printf( ic, "%s", text );
[b17ce85]480       
481        return TRUE;
[aea8b68]482}
483
[a87754b]484static gboolean bee_irc_chat_msg( bee_t *bee, struct groupchat *c, bee_user_t *bu, const char *msg, time_t sent_at )
[aea8b68]485{
[27e2c66]486        irc_t *irc = bee->ui_data;
487        irc_user_t *iu = bu->ui_data;
488        irc_channel_t *ic = c->ui_data;
489        char *ts = NULL;
490       
[b1af3e8]491        if( ic == NULL )
492                return FALSE;
493       
[27e2c66]494        if( sent_at > 0 && set_getbool( &bee->set, "display_timestamps" ) )
495                ts = irc_format_timestamp( irc, sent_at );
496       
497        irc_send_msg( iu, "PRIVMSG", ic->name, msg, ts );
498        g_free( ts );
499       
500        return TRUE;
[aea8b68]501}
502
[a87754b]503static gboolean bee_irc_chat_add_user( bee_t *bee, struct groupchat *c, bee_user_t *bu )
[aea8b68]504{
505        irc_t *irc = bee->ui_data;
[b1af3e8]506        irc_channel_t *ic = c->ui_data;
[aea8b68]507       
[b1af3e8]508        if( ic == NULL )
509                return FALSE;
510       
511        irc_channel_add_user( ic, bu == bee->user ? irc->user : bu->ui_data );
[b17ce85]512       
513        return TRUE;
[aea8b68]514}
515
[a87754b]516static gboolean bee_irc_chat_remove_user( bee_t *bee, struct groupchat *c, bee_user_t *bu )
[aea8b68]517{
[b17ce85]518        irc_t *irc = bee->ui_data;
[b1af3e8]519        irc_channel_t *ic = c->ui_data;
520       
521        if( ic == NULL )
522                return FALSE;
[b17ce85]523       
[1c40aa7]524        /* TODO: Possible bug here: If a module removes $user here instead of just
525           using imcb_chat_free() and the channel was IRC_CHANNEL_TEMP, we get into
526           a broken state around here. */
[b1af3e8]527        irc_channel_del_user( ic, bu == bee->user ? irc->user : bu->ui_data, IRC_CDU_PART, NULL );
[b17ce85]528       
529        return TRUE;
[aea8b68]530}
531
[9e27f18]532static gboolean bee_irc_chat_topic( bee_t *bee, struct groupchat *c, const char *new, bee_user_t *bu )
533{
[b1af3e8]534        irc_channel_t *ic = c->ui_data;
[9e27f18]535        irc_t *irc = bee->ui_data;
536        irc_user_t *iu;
537       
[b1af3e8]538        if( ic == NULL )
539                return FALSE;
540       
[9e27f18]541        if( bu == NULL )
542                iu = irc->root;
543        else if( bu == bee->user )
544                iu = irc->user;
545        else
546                iu = bu->ui_data;
547       
[b1af3e8]548        irc_channel_set_topic( ic, new, iu );
[9e27f18]549       
550        return TRUE;
551}
552
[d343eaa]553static gboolean bee_irc_chat_name_hint( bee_t *bee, struct groupchat *c, const char *name )
554{
555        irc_t *irc = bee->ui_data;
[52a2521]556        irc_channel_t *ic = c->ui_data, *oic;
[d343eaa]557        char stripped[MAX_NICK_LENGTH+1], *full_name;
558       
[b1af3e8]559        if( ic == NULL )
560                return FALSE;
561       
[d343eaa]562        /* Don't rename a channel if the user's in it already. */
563        if( ic->flags & IRC_CHANNEL_JOINED )
564                return FALSE;
565       
566        strncpy( stripped, name, MAX_NICK_LENGTH );
567        stripped[MAX_NICK_LENGTH] = '\0';
[134a02c]568        irc_channel_name_strip( stripped );
[d343eaa]569        if( set_getbool( &bee->set, "lcnicks" ) )
570                nick_lc( stripped );
571       
[52a2521]572        if( stripped[0] == '\0' )
573                return FALSE;
[d343eaa]574       
[52a2521]575        full_name = g_strdup_printf( "#%s", stripped );
576        if( ( oic = irc_channel_by_name( irc, full_name ) ) )
[d343eaa]577        {
[52a2521]578                char *type, *chat_type;
579               
580                type = set_getstr( &oic->set, "type" );
581                chat_type = set_getstr( &oic->set, "chat_type" );
582               
583                if( type && chat_type && oic->data == FALSE &&
584                    strcmp( type, "chat" ) == 0 &&
585                    strcmp( chat_type, "groupchat" ) == 0 )
586                {
587                        /* There's a channel with this name already, but it looks
588                           like it's not in use yet. Most likely the IRC client
589                           rejoined the channel after a reconnect. Remove it so
590                           we can reuse its name. */
591                        irc_channel_free( oic );
592                }
593                else
594                {
595                        g_free( full_name );
596                        return FALSE;
597                }
[d343eaa]598        }
599       
[52a2521]600        g_free( ic->name );
601        ic->name = full_name;
602       
[d343eaa]603        return TRUE;
604}
605
[a87754b]606/* IRC->IM */
[619dd18]607static gboolean bee_irc_channel_chat_privmsg_cb( gpointer data, gint fd, b_input_condition cond );
608
[a87754b]609static gboolean bee_irc_channel_chat_privmsg( irc_channel_t *ic, const char *msg )
610{
611        struct groupchat *c = ic->data;
[69b896b]612        char *trans = NULL, *s;
[a87754b]613       
[5a75d15]614        if( c == NULL )
615                return FALSE;
[69b896b]616       
617        if( set_getbool( &ic->set, "translate_to_nicks" ) )
618        {
619                char nick[MAX_NICK_LENGTH+1];
620                irc_user_t *iu;
621               
622                strncpy( nick, msg, MAX_NICK_LENGTH );
623                nick[MAX_NICK_LENGTH] = '\0';
624                if( ( s = strchr( nick, ':' ) ) || ( s = strchr( nick, ',' ) ) )
625                {
626                        *s = '\0';
627                        if( ( iu = irc_user_by_name( ic->irc, nick ) ) &&
628                            iu->bu->nick && irc_channel_has_user( ic, iu ) )
629                        {
630                                trans = g_strconcat( iu->bu->nick, msg + ( s - nick ), NULL );
631                                msg = trans;
632                        }
633                }
634        }
635       
636        if( set_getbool( &ic->irc->b->set, "paste_buffer" ) )
[619dd18]637        {
638                int delay;
639               
640                if( ic->pastebuf == NULL )
641                        ic->pastebuf = g_string_new( msg );
642                else
643                {
644                        b_event_remove( ic->pastebuf_timer );
645                        g_string_append_printf( ic->pastebuf, "\n%s", msg );
646                }
647               
648                if( ( delay = set_getint( &ic->irc->b->set, "paste_buffer_delay" ) ) <= 5 )
649                        delay *= 1000;
650               
651                ic->pastebuf_timer = b_timeout_add( delay, bee_irc_channel_chat_privmsg_cb, ic );
652               
[69b896b]653                g_free( trans );
[619dd18]654                return TRUE;
655        }
656        else
657                bee_chat_msg( ic->irc->b, c, msg, 0 );
[a87754b]658       
[69b896b]659        g_free( trans );
[a87754b]660        return TRUE;
[5a75d15]661}
662
[619dd18]663static gboolean bee_irc_channel_chat_privmsg_cb( gpointer data, gint fd, b_input_condition cond )
664{
665        irc_channel_t *ic = data;
666       
667        bee_chat_msg( ic->irc->b, ic->data, ic->pastebuf->str, 0 );
668       
669        g_string_free( ic->pastebuf, TRUE );
670        ic->pastebuf = 0;
671        ic->pastebuf_timer = 0;
672       
673        return FALSE;
674}
675
[5a75d15]676static gboolean bee_irc_channel_chat_join( irc_channel_t *ic )
677{
678        char *acc_s, *room;
679        account_t *acc;
[a87754b]680       
[5a75d15]681        if( strcmp( set_getstr( &ic->set, "chat_type" ), "room" ) != 0 )
682                return TRUE;
683       
684        if( ( acc_s = set_getstr( &ic->set, "account" ) ) &&
685            ( room = set_getstr( &ic->set, "room" ) ) &&
686            ( acc = account_get( ic->irc->b, acc_s ) ) &&
687            acc->ic && acc->prpl->chat_join )
688        {
689                char *nick;
690               
691                if( !( nick = set_getstr( &ic->set, "nick" ) ) )
692                        nick = ic->irc->user->nick;
693               
694                ic->flags |= IRC_CHANNEL_CHAT_PICKME;
[03f3828]695                acc->prpl->chat_join( acc->ic, room, nick, NULL, &ic->set );
[5a75d15]696                ic->flags &= ~IRC_CHANNEL_CHAT_PICKME;
697               
698                return FALSE;
699        }
700        else
701        {
702                irc_send_num( ic->irc, 403, "%s :Can't join channel, account offline?", ic->name );
703                return FALSE;
704        }
[a87754b]705}
706
[bfb99ee]707static gboolean bee_irc_channel_chat_part( irc_channel_t *ic, const char *msg )
708{
709        struct groupchat *c = ic->data;
710       
[5a75d15]711        if( c && c->ic->acc->prpl->chat_leave )
[bfb99ee]712                c->ic->acc->prpl->chat_leave( c );
713       
714        return TRUE;
715}
716
[9e27f18]717static gboolean bee_irc_channel_chat_topic( irc_channel_t *ic, const char *new )
718{
[4469e7e]719        struct groupchat *c = ic->data;
[5a75d15]720       
721        if( c == NULL )
722                return FALSE;
[4469e7e]723       
724        if( c->ic->acc->prpl->chat_topic == NULL )
725                irc_send_num( ic->irc, 482, "%s :IM network does not support channel topics", ic->name );
726        else
727        {
[5a75d15]728                /* TODO: Need more const goodness here, sigh */
729                char *topic = g_strdup( new );
[4469e7e]730                c->ic->acc->prpl->chat_topic( c, topic );
[5a75d15]731                g_free( topic );
[4469e7e]732                return TRUE;
733        }
734               
735        return FALSE;
[9e27f18]736}
737
[66b9e36a]738static gboolean bee_irc_channel_chat_invite( irc_channel_t *ic, irc_user_t *iu )
739{
740        struct groupchat *c = ic->data;
[5a75d15]741        bee_user_t *bu = iu->bu;
742       
743        if( bu == NULL )
744                return FALSE;
[66b9e36a]745       
[5a75d15]746        if( c )
747        {
748                if( iu->bu->ic != c->ic )
749                        irc_send_num( ic->irc, 482, "%s :Can't mix different IM networks in one groupchat", ic->name );
750                else if( c->ic->acc->prpl->chat_invite )
751                        c->ic->acc->prpl->chat_invite( c, iu->bu->handle, NULL );
752                else
753                        irc_send_num( ic->irc, 482, "%s :IM protocol does not support room invitations", ic->name );
754        }
755        else if( bu->ic->acc->prpl->chat_with &&
756                 strcmp( set_getstr( &ic->set, "chat_type" ), "groupchat" ) == 0 )
757        {
758                ic->flags |= IRC_CHANNEL_CHAT_PICKME;
759                iu->bu->ic->acc->prpl->chat_with( bu->ic, bu->handle );
760                ic->flags &= ~IRC_CHANNEL_CHAT_PICKME;
761        }
[66b9e36a]762        else
[5a75d15]763        {
[66b9e36a]764                irc_send_num( ic->irc, 482, "%s :IM protocol does not support room invitations", ic->name );
[5a75d15]765        }
[66b9e36a]766       
767        return TRUE;
768}
769
[5a75d15]770static char *set_eval_room_account( set_t *set, char *value );
[1c40aa7]771static char *set_eval_chat_type( set_t *set, char *value );
[5a75d15]772
773static gboolean bee_irc_channel_init( irc_channel_t *ic )
774{
775        set_add( &ic->set, "account", NULL, set_eval_room_account, ic );
[1c40aa7]776        set_add( &ic->set, "chat_type", "groupchat", set_eval_chat_type, ic );
[5a75d15]777        set_add( &ic->set, "nick", NULL, NULL, ic );
778        set_add( &ic->set, "room", NULL, NULL, ic );
[69b896b]779        set_add( &ic->set, "translate_to_nicks", "true", set_eval_bool, ic );
[5a75d15]780       
[1c40aa7]781        /* chat_type == groupchat */
782        ic->flags |= IRC_CHANNEL_TEMP;
783       
[5a75d15]784        return TRUE;
785}
786
787static char *set_eval_room_account( set_t *set, char *value )
788{
789        struct irc_channel *ic = set->data;
[03f3828]790        account_t *acc, *oa;
[5a75d15]791       
792        if( !( acc = account_get( ic->irc->b, value ) ) )
793                return SET_INVALID;
794        else if( !acc->prpl->chat_join )
795        {
796                irc_usermsg( ic->irc, "Named chatrooms not supported on that account." );
797                return SET_INVALID;
798        }
799       
[03f3828]800        if( set->value && ( oa = account_get( ic->irc->b, set->value ) ) &&
801            oa->prpl->chat_free_settings )
802                oa->prpl->chat_free_settings( oa, &ic->set );
803       
804        if( acc->prpl->chat_add_settings )
805                acc->prpl->chat_add_settings( acc, &ic->set );
806       
[5a75d15]807        return g_strdup_printf( "%s(%s)", acc->prpl->name, acc->user );
808}
809
[1c40aa7]810static char *set_eval_chat_type( set_t *set, char *value )
811{
812        struct irc_channel *ic = set->data;
813       
814        if( strcmp( value, "groupchat" ) == 0 )
815                ic->flags |= IRC_CHANNEL_TEMP;
816        else if( strcmp( value, "room" ) == 0 )
817                ic->flags &= ~IRC_CHANNEL_TEMP;
818        else
819                return NULL;
820       
821        return value;
822}
823
[5a75d15]824static gboolean bee_irc_channel_free( irc_channel_t *ic )
825{
[b1af3e8]826        struct groupchat *c = ic->data;
827       
[5a75d15]828        set_del( &ic->set, "account" );
829        set_del( &ic->set, "chat_type" );
830        set_del( &ic->set, "nick" );
831        set_del( &ic->set, "room" );
[69b896b]832        set_del( &ic->set, "translate_to_nicks" );
[5a75d15]833       
[1c40aa7]834        ic->flags &= ~IRC_CHANNEL_TEMP;
835       
[b1af3e8]836        /* That one still points at this channel. Don't. */
837        if( c )
838                c->ui_data = NULL;
839       
[5a75d15]840        return TRUE;
841}
842
843const struct irc_channel_funcs irc_channel_im_chat_funcs = {
[a87754b]844        bee_irc_channel_chat_privmsg,
[5a75d15]845        bee_irc_channel_chat_join,
[bfb99ee]846        bee_irc_channel_chat_part,
[9e27f18]847        bee_irc_channel_chat_topic,
[66b9e36a]848        bee_irc_channel_chat_invite,
[5a75d15]849
850        bee_irc_channel_init,
851        bee_irc_channel_free,
[a87754b]852};
853
[aea8b68]854
[e4816ea]855/* IM->IRC: File transfers */
[17a6ee9]856static file_transfer_t *bee_irc_ft_in_start( bee_t *bee, bee_user_t *bu, const char *file_name, size_t file_size )
857{
858        return dccs_send_start( bu->ic, (irc_user_t *) bu->ui_data, file_name, file_size );
859}
860
[a87754b]861static gboolean bee_irc_ft_out_start( struct im_connection *ic, file_transfer_t *ft )
[17a6ee9]862{
863        return dccs_recv_start( ft );
864}
865
[a87754b]866static void bee_irc_ft_close( struct im_connection *ic, file_transfer_t *ft )
[17a6ee9]867{
868        return dcc_close( ft );
869}
870
[a87754b]871static void bee_irc_ft_finished( struct im_connection *ic, file_transfer_t *file )
[17a6ee9]872{
873        dcc_file_transfer_t *df = file->priv;
874
875        if( file->bytes_transferred >= file->file_size )
876                dcc_finish( file );
877        else
878                df->proto_finished = TRUE;
879}
880
[d860a8d]881const struct bee_ui_funcs irc_ui_funcs = {
[5c7b45c]882        bee_irc_imc_connected,
883        bee_irc_imc_disconnected,
884       
[81e04e1]885        bee_irc_user_new,
[d860a8d]886        bee_irc_user_free,
[1d39159]887        bee_irc_user_fullname,
[6ef9065]888        bee_irc_user_nick_hint,
[7e83e8e4]889        bee_irc_user_group,
[d860a8d]890        bee_irc_user_status,
[f012a9f]891        bee_irc_user_msg,
[573dab0]892        bee_irc_user_typing,
[17a6ee9]893       
[aea8b68]894        bee_irc_chat_new,
895        bee_irc_chat_free,
[27e2c66]896        bee_irc_chat_log,
897        bee_irc_chat_msg,
[aea8b68]898        bee_irc_chat_add_user,
[b17ce85]899        bee_irc_chat_remove_user,
[9e27f18]900        bee_irc_chat_topic,
[d343eaa]901        bee_irc_chat_name_hint,
[aea8b68]902       
[17a6ee9]903        bee_irc_ft_in_start,
904        bee_irc_ft_out_start,
905        bee_irc_ft_close,
906        bee_irc_ft_finished,
[81e04e1]907};
Note: See TracBrowser for help on using the repository browser.