source: irc_im.c @ 762d96f

Last change on this file since 762d96f was ac2717b, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-08-14T10:55:20Z

blist should only show contacts that are (or would be if they were online)
in the current channel.

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