source: irc_im.c @ d7f8500

Last change on this file since d7f8500 was 7a6ba50, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-06-29T23:44:17Z

Also allow selecting contacts for a channel by protocol instead of account.
If someone has two MSN accts and wants contacts from both in one channel,
this is now possible.

  • Property mode set to 100644
File size: 20.4 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 gboolean bee_irc_user_new( bee_t *bee, bee_user_t *bu )
34{
35        irc_user_t *iu;
36        irc_t *irc = (irc_t*) bee->ui_data;
37        char nick[MAX_NICK_LENGTH+1], *s;
38       
39        memset( nick, 0, MAX_NICK_LENGTH + 1 );
40        strcpy( nick, nick_get( bu->ic->acc, bu->handle ) );
41       
42        bu->ui_data = iu = irc_user_new( irc, nick );
43        iu->bu = bu;
44       
45        if( ( s = strchr( bu->handle, '@' ) ) )
46        {
47                iu->host = g_strdup( s + 1 );
48                iu->user = g_strndup( bu->handle, s - bu->handle );
49        }
50        else if( bu->ic->acc->server )
51        {
52                iu->host = g_strdup( bu->ic->acc->server );
53                iu->user = g_strdup( bu->handle );
54               
55                /* s/ /_/ ... important for AOL screennames */
56                for( s = iu->user; *s; s ++ )
57                        if( *s == ' ' )
58                                *s = '_';
59        }
60        else
61        {
62                iu->host = g_strdup( bu->ic->acc->prpl->name );
63                iu->user = g_strdup( bu->handle );
64        }
65       
66        if( bu->flags & BEE_USER_LOCAL )
67        {
68                char *s = set_getstr( &bee->set, "handle_unknown" );
69               
70                if( strcmp( s, "add_private" ) == 0 )
71                        iu->last_channel = NULL;
72                else if( strcmp( s, "add_channel" ) == 0 )
73                        iu->last_channel = irc->default_channel;
74        }
75       
76        iu->f = &irc_user_im_funcs;
77       
78        return TRUE;
79}
80
81static gboolean bee_irc_user_free( bee_t *bee, bee_user_t *bu )
82{
83        return irc_user_free( bee->ui_data, (irc_user_t *) bu->ui_data );
84}
85
86static gboolean bee_irc_user_status( bee_t *bee, bee_user_t *bu, bee_user_t *old )
87{
88        irc_t *irc = bee->ui_data;
89        irc_user_t *iu = bu->ui_data;
90       
91        /* Do this outside the if below since away state can change without
92           the online state changing. */
93        iu->flags &= ~IRC_USER_AWAY;
94        if( bu->flags & BEE_USER_AWAY || !( bu->flags & BEE_USER_ONLINE ) )
95                iu->flags |= IRC_USER_AWAY;
96       
97        if( ( bu->flags & BEE_USER_ONLINE ) != ( old->flags & BEE_USER_ONLINE ) )
98        {
99                if( bu->flags & BEE_USER_ONLINE )
100                {
101                        if( g_hash_table_lookup( irc->watches, iu->key ) )
102                                irc_send_num( irc, 600, "%s %s %s %d :%s", iu->nick, iu->user,
103                                              iu->host, (int) time( NULL ), "logged online" );
104                }
105                else
106                {
107                        if( g_hash_table_lookup( irc->watches, iu->key ) )
108                                irc_send_num( irc, 601, "%s %s %s %d :%s", iu->nick, iu->user,
109                                              iu->host, (int) time( NULL ), "logged offline" );
110                }
111        }
112       
113        /* Reset this one since the info may have changed. */
114        iu->away_reply_timeout = 0;
115       
116        bee_irc_channel_update( irc, NULL, iu );
117       
118        return TRUE;
119}
120
121void bee_irc_channel_update( irc_t *irc, irc_channel_t *ic, irc_user_t *iu )
122{
123        struct irc_control_channel *icc;
124        GSList *l;
125        gboolean show;
126       
127        if( ic == NULL )
128        {
129                for( l = irc->channels; l; l = l->next )
130                {
131                        ic = l->data;
132                        /* TODO: Just add a type flag or so.. */
133                        if( ic->f == irc->default_channel->f )
134                                bee_irc_channel_update( irc, ic, iu );
135                }
136                return;
137        }
138        if( iu == NULL )
139        {
140                for( l = irc->users; l; l = l->next )
141                {
142                        iu = l->data;
143                        if( iu->bu )
144                                bee_irc_channel_update( irc, ic, l->data );
145                }
146                return;
147        }
148       
149        icc = ic->data;
150       
151        if( !( iu->bu->flags & BEE_USER_ONLINE ) )
152                show = FALSE;
153        else if( icc->type == IRC_CC_TYPE_DEFAULT )
154                show = TRUE;
155        else if( icc->type == IRC_CC_TYPE_GROUP )
156                show = iu->bu->group == icc->group;
157        else if( icc->type == IRC_CC_TYPE_ACCOUNT )
158                show = iu->bu->ic->acc == icc->account;
159        else if( icc->type == IRC_CC_TYPE_PROTOCOL )
160                show = iu->bu->ic->acc->prpl == icc->protocol;
161       
162        if( !show )
163        {
164                irc_channel_del_user( ic, iu, FALSE, NULL );
165        }
166        else
167        {
168                irc_channel_add_user( ic, iu );
169               
170                if( set_getbool( &irc->b->set, "away_devoice" ) )
171                        irc_channel_user_set_mode( ic, iu, ( iu->bu->flags & BEE_USER_AWAY ) ?
172                                                   0 : IRC_CHANNEL_USER_VOICE );
173                else
174                        irc_channel_user_set_mode( ic, iu, 0 );
175        }
176}
177
178static gboolean bee_irc_user_msg( bee_t *bee, bee_user_t *bu, const char *msg, time_t sent_at )
179{
180        irc_t *irc = bee->ui_data;
181        irc_user_t *iu = (irc_user_t *) bu->ui_data;
182        char *dst, *prefix = NULL;
183        char *wrapped, *ts = NULL;
184       
185        if( sent_at > 0 && set_getbool( &irc->b->set, "display_timestamps" ) )
186                ts = irc_format_timestamp( irc, sent_at );
187       
188        if( iu->last_channel )
189        {
190                dst = iu->last_channel->name;
191                prefix = g_strdup_printf( "%s%s%s", irc->user->nick, set_getstr( &bee->set, "to_char" ), ts ? : "" );
192        }
193        else
194        {
195                dst = irc->user->nick;
196                prefix = ts;
197                ts = NULL;
198        }
199       
200        wrapped = word_wrap( msg, 425 );
201        irc_send_msg( iu, "PRIVMSG", dst, wrapped, prefix );
202       
203        g_free( wrapped );
204        g_free( prefix );
205        g_free( ts );
206       
207        return TRUE;
208}
209
210static gboolean bee_irc_user_typing( bee_t *bee, bee_user_t *bu, uint32_t flags )
211{
212        irc_t *irc = (irc_t *) bee->ui_data;
213       
214        if( set_getbool( &bee->set, "typing_notice" ) )
215                irc_send_msg_f( (irc_user_t *) bu->ui_data, "PRIVMSG", irc->user->nick,
216                                "\001TYPING %d\001", ( flags >> 8 ) & 3 );
217        else
218                return FALSE;
219       
220        return TRUE;
221}
222
223static gboolean bee_irc_user_nick_hint( bee_t *bee, bee_user_t *bu, const char *hint );
224
225static gboolean bee_irc_user_fullname( bee_t *bee, bee_user_t *bu )
226{
227        irc_user_t *iu = (irc_user_t *) bu->ui_data;
228        irc_t *irc = (irc_t *) bee->ui_data;
229        char *s;
230       
231        if( iu->fullname != iu->nick )
232                g_free( iu->fullname );
233        iu->fullname = g_strdup( bu->fullname );
234       
235        /* Strip newlines (unlikely, but IRC-unfriendly so they must go)
236           TODO(wilmer): Do the same with away msgs again! */
237        for( s = iu->fullname; *s; s ++ )
238                if( isspace( *s ) ) *s = ' ';
239       
240        if( ( bu->ic->flags & OPT_LOGGED_IN ) && set_getbool( &bee->set, "display_namechanges" ) )
241        {
242                char *msg = g_strdup_printf( "<< \002BitlBee\002 - Changed name to `%s' >>", iu->fullname );
243                irc_send_msg( iu, "NOTICE", irc->user->nick, msg, NULL );
244        }
245       
246        s = set_getstr( &bu->ic->acc->set, "nick_source" );
247        if( strcmp( s, "handle" ) != 0 )
248        {
249                char *name = g_strdup( bu->fullname );
250               
251                if( strcmp( s, "first_name" ) == 0 )
252                {
253                        int i;
254                        for( i = 0; name[i] && !isspace( name[i] ); i ++ ) {}
255                        name[i] = '\0';
256                }
257               
258                bee_irc_user_nick_hint( bee, bu, name );
259               
260                g_free( name );
261        }
262       
263        return TRUE;
264}
265
266static gboolean bee_irc_user_nick_hint( bee_t *bee, bee_user_t *bu, const char *hint )
267{
268        irc_user_t *iu = bu->ui_data;
269        char newnick[MAX_NICK_LENGTH+1], *translit;
270       
271        if( bu->flags & BEE_USER_ONLINE )
272                /* Ignore if the user is visible already. */
273                return TRUE;
274       
275        if( nick_saved( bu->ic->acc, bu->handle ) )
276                /* The user already assigned a nickname to this person. */
277                return TRUE;
278       
279        /* Credits to Josay_ in #bitlbee for this idea. //TRANSLIT should
280           do lossy/approximate conversions, so letters with accents don't
281           just get stripped. Note that it depends on LC_CTYPE being set to
282           something other than C/POSIX. */
283        translit = g_convert( hint, -1, "ASCII//TRANSLIT//IGNORE", "UTF-8",
284                              NULL, NULL, NULL );
285       
286        strncpy( newnick, translit ? : hint, MAX_NICK_LENGTH );
287        newnick[MAX_NICK_LENGTH] = 0;
288        g_free( translit );
289       
290        /* Some processing to make sure this string is a valid IRC nickname. */
291        nick_strip( newnick );
292        if( set_getbool( &bee->set, "lcnicks" ) )
293                nick_lc( newnick );
294       
295        if( strcmp( iu->nick, newnick ) != 0 )
296        {
297                /* Only do this if newnick is different from the current one.
298                   If rejoining a channel, maybe we got this nick already
299                   (and dedupe would only add an underscore. */
300                nick_dedupe( bu->ic->acc, bu->handle, newnick );
301                irc_user_set_nick( iu, newnick );
302        }
303       
304        return TRUE;
305}
306
307static gboolean bee_irc_user_group( bee_t *bee, bee_user_t *bu )
308{
309        irc_user_t *iu = (irc_user_t *) bu->ui_data;
310        irc_t *irc = (irc_t *) bee->ui_data;
311       
312        bee_irc_channel_update( irc, NULL, iu );
313       
314        return TRUE;
315}
316
317/* IRC->IM calls */
318
319static gboolean bee_irc_user_privmsg_cb( gpointer data, gint fd, b_input_condition cond );
320
321static gboolean bee_irc_user_privmsg( irc_user_t *iu, const char *msg )
322{
323        const char *away;
324       
325        if( iu->bu == NULL )
326                return FALSE;
327       
328        if( ( away = irc_user_get_away( iu ) ) &&
329            time( NULL ) >= iu->away_reply_timeout )
330        {
331                irc_send_num( iu->irc, 301, "%s :%s", iu->nick, away );
332                iu->away_reply_timeout = time( NULL ) +
333                        set_getint( &iu->irc->b->set, "away_reply_timeout" );
334        }
335       
336        if( set_getbool( &iu->irc->b->set, "paste_buffer" ) )
337        {
338                int delay;
339               
340                if( iu->pastebuf == NULL )
341                        iu->pastebuf = g_string_new( msg );
342                else
343                {
344                        b_event_remove( iu->pastebuf_timer );
345                        g_string_append_printf( iu->pastebuf, "\n%s", msg );
346                }
347               
348                if( ( delay = set_getint( &iu->irc->b->set, "paste_buffer_delay" ) ) <= 5 )
349                        delay *= 1000;
350               
351                iu->pastebuf_timer = b_timeout_add( delay, bee_irc_user_privmsg_cb, iu );
352               
353                return TRUE;
354        }
355        else
356                return bee_user_msg( iu->irc->b, iu->bu, msg, 0 );
357}
358
359static gboolean bee_irc_user_privmsg_cb( gpointer data, gint fd, b_input_condition cond )
360{
361        irc_user_t *iu = data;
362       
363        bee_user_msg( iu->irc->b, iu->bu, iu->pastebuf->str, 0 );
364       
365        g_string_free( iu->pastebuf, TRUE );
366        iu->pastebuf = 0;
367        iu->pastebuf_timer = 0;
368       
369        return FALSE;
370}
371
372static gboolean bee_irc_user_ctcp( irc_user_t *iu, char *const *ctcp )
373{
374        if( ctcp[1] && g_strcasecmp( ctcp[0], "DCC" ) == 0
375                    && g_strcasecmp( ctcp[1], "SEND" ) == 0 )
376        {
377                if( iu->bu && iu->bu->ic && iu->bu->ic->acc->prpl->transfer_request )
378                {
379                        file_transfer_t *ft = dcc_request( iu->bu->ic, ctcp );
380                        if ( ft )
381                                iu->bu->ic->acc->prpl->transfer_request( iu->bu->ic, ft, iu->bu->handle );
382                       
383                        return TRUE;
384                }
385        }
386        else if( g_strcasecmp( ctcp[0], "TYPING" ) == 0 )
387        {
388                if( iu->bu && iu->bu->ic && iu->bu->ic->acc->prpl->send_typing && ctcp[1] )
389                {
390                        int st = ctcp[1][0];
391                        if( st >= '0' && st <= '2' )
392                        {
393                                st <<= 8;
394                                iu->bu->ic->acc->prpl->send_typing( iu->bu->ic, iu->bu->handle, st );
395                        }
396                       
397                        return TRUE;
398                }
399        }
400       
401        return FALSE;
402}
403
404static const struct irc_user_funcs irc_user_im_funcs = {
405        bee_irc_user_privmsg,
406        bee_irc_user_ctcp,
407};
408
409
410/* IM->IRC: Groupchats */
411const struct irc_channel_funcs irc_channel_im_chat_funcs;
412
413static gboolean bee_irc_chat_new( bee_t *bee, struct groupchat *c )
414{
415        irc_t *irc = bee->ui_data;
416        irc_channel_t *ic;
417        char *topic;
418        GSList *l;
419        int i;
420       
421        /* Try to find a channel that expects to receive a groupchat.
422           This flag is set by groupchat_stub_invite(). */
423        for( l = irc->channels; l; l = l->next )
424        {
425                ic = l->data;
426                if( ic->flags & IRC_CHANNEL_CHAT_PICKME )
427                        break;
428        }
429       
430        /* If we found none, just generate some stupid name. */
431        if( l == NULL ) for( i = 0; i <= 999; i ++ )
432        {
433                char name[16];
434                sprintf( name, "#chat_%03d", i );
435                if( ( ic = irc_channel_new( irc, name ) ) )
436                        break;
437        }
438       
439        if( ic == NULL )
440                return FALSE;
441       
442        c->ui_data = ic;
443        ic->data = c;
444       
445        topic = g_strdup_printf( "BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!", c->title );
446        irc_channel_set_topic( ic, topic, irc->root );
447        g_free( topic );
448       
449        return TRUE;
450}
451
452static gboolean bee_irc_chat_free( bee_t *bee, struct groupchat *c )
453{
454        irc_channel_t *ic = c->ui_data;
455       
456        if( ic->flags & IRC_CHANNEL_JOINED )
457                irc_channel_printf( ic, "Cleaning up channel, bye!" );
458       
459        ic->data = NULL;
460        irc_channel_del_user( ic, ic->irc->user, FALSE, "Chatroom closed by server" );
461       
462        return TRUE;
463}
464
465static gboolean bee_irc_chat_log( bee_t *bee, struct groupchat *c, const char *text )
466{
467        irc_channel_t *ic = c->ui_data;
468       
469        irc_channel_printf( ic, "%s", text );
470       
471        return TRUE;
472}
473
474static gboolean bee_irc_chat_msg( bee_t *bee, struct groupchat *c, bee_user_t *bu, const char *msg, time_t sent_at )
475{
476        irc_t *irc = bee->ui_data;
477        irc_user_t *iu = bu->ui_data;
478        irc_channel_t *ic = c->ui_data;
479        char *ts = NULL;
480       
481        if( sent_at > 0 && set_getbool( &bee->set, "display_timestamps" ) )
482                ts = irc_format_timestamp( irc, sent_at );
483       
484        irc_send_msg( iu, "PRIVMSG", ic->name, msg, ts );
485        g_free( ts );
486       
487        return TRUE;
488}
489
490static gboolean bee_irc_chat_add_user( bee_t *bee, struct groupchat *c, bee_user_t *bu )
491{
492        irc_t *irc = bee->ui_data;
493       
494        irc_channel_add_user( c->ui_data, bu == bee->user ? irc->user : bu->ui_data );
495       
496        return TRUE;
497}
498
499static gboolean bee_irc_chat_remove_user( bee_t *bee, struct groupchat *c, bee_user_t *bu )
500{
501        irc_t *irc = bee->ui_data;
502       
503        /* TODO: Possible bug here: If a module removes $user here instead of just
504           using imcb_chat_free() and the channel was IRC_CHANNEL_TEMP, we get into
505           a broken state around here. */
506        irc_channel_del_user( c->ui_data, bu == bee->user ? irc->user : bu->ui_data, FALSE, NULL );
507       
508        return TRUE;
509}
510
511static gboolean bee_irc_chat_topic( bee_t *bee, struct groupchat *c, const char *new, bee_user_t *bu )
512{
513        irc_t *irc = bee->ui_data;
514        irc_user_t *iu;
515       
516        if( bu == NULL )
517                iu = irc->root;
518        else if( bu == bee->user )
519                iu = irc->user;
520        else
521                iu = bu->ui_data;
522       
523        irc_channel_set_topic( c->ui_data, new, iu );
524       
525        return TRUE;
526}
527
528static gboolean bee_irc_chat_name_hint( bee_t *bee, struct groupchat *c, const char *name )
529{
530        irc_t *irc = bee->ui_data;
531        irc_channel_t *ic = c->ui_data;
532        char stripped[MAX_NICK_LENGTH+1], *full_name;
533       
534        /* Don't rename a channel if the user's in it already. */
535        if( ic->flags & IRC_CHANNEL_JOINED )
536                return FALSE;
537       
538        strncpy( stripped, name, MAX_NICK_LENGTH );
539        stripped[MAX_NICK_LENGTH] = '\0';
540        irc_channel_name_strip( stripped );
541        if( set_getbool( &bee->set, "lcnicks" ) )
542                nick_lc( stripped );
543       
544        full_name = g_strdup_printf( "#%s", stripped );
545       
546        if( stripped[0] && irc_channel_by_name( irc, full_name ) == NULL )
547        {
548                g_free( ic->name );
549                ic->name = full_name;
550        }
551        else
552        {
553                g_free( full_name );
554        }
555       
556        return TRUE;
557}
558
559/* IRC->IM */
560static gboolean bee_irc_channel_chat_privmsg_cb( gpointer data, gint fd, b_input_condition cond );
561
562static gboolean bee_irc_channel_chat_privmsg( irc_channel_t *ic, const char *msg )
563{
564        struct groupchat *c = ic->data;
565       
566        if( c == NULL )
567                return FALSE;
568        else if( set_getbool( &ic->irc->b->set, "paste_buffer" ) )
569        {
570                int delay;
571               
572                if( ic->pastebuf == NULL )
573                        ic->pastebuf = g_string_new( msg );
574                else
575                {
576                        b_event_remove( ic->pastebuf_timer );
577                        g_string_append_printf( ic->pastebuf, "\n%s", msg );
578                }
579               
580                if( ( delay = set_getint( &ic->irc->b->set, "paste_buffer_delay" ) ) <= 5 )
581                        delay *= 1000;
582               
583                ic->pastebuf_timer = b_timeout_add( delay, bee_irc_channel_chat_privmsg_cb, ic );
584               
585                return TRUE;
586        }
587        else
588                bee_chat_msg( ic->irc->b, c, msg, 0 );
589       
590        return TRUE;
591}
592
593static gboolean bee_irc_channel_chat_privmsg_cb( gpointer data, gint fd, b_input_condition cond )
594{
595        irc_channel_t *ic = data;
596       
597        bee_chat_msg( ic->irc->b, ic->data, ic->pastebuf->str, 0 );
598       
599        g_string_free( ic->pastebuf, TRUE );
600        ic->pastebuf = 0;
601        ic->pastebuf_timer = 0;
602       
603        return FALSE;
604}
605
606static gboolean bee_irc_channel_chat_join( irc_channel_t *ic )
607{
608        char *acc_s, *room;
609        account_t *acc;
610       
611        if( strcmp( set_getstr( &ic->set, "chat_type" ), "room" ) != 0 )
612                return TRUE;
613       
614        if( ( acc_s = set_getstr( &ic->set, "account" ) ) &&
615            ( room = set_getstr( &ic->set, "room" ) ) &&
616            ( acc = account_get( ic->irc->b, acc_s ) ) &&
617            acc->ic && acc->prpl->chat_join )
618        {
619                char *nick;
620               
621                if( !( nick = set_getstr( &ic->set, "nick" ) ) )
622                        nick = ic->irc->user->nick;
623               
624                ic->flags |= IRC_CHANNEL_CHAT_PICKME;
625                acc->prpl->chat_join( acc->ic, room, nick, NULL );
626                ic->flags &= ~IRC_CHANNEL_CHAT_PICKME;
627               
628                return FALSE;
629        }
630        else
631        {
632                irc_send_num( ic->irc, 403, "%s :Can't join channel, account offline?", ic->name );
633                return FALSE;
634        }
635}
636
637static gboolean bee_irc_channel_chat_part( irc_channel_t *ic, const char *msg )
638{
639        struct groupchat *c = ic->data;
640       
641        if( c && c->ic->acc->prpl->chat_leave )
642                c->ic->acc->prpl->chat_leave( c );
643       
644        return TRUE;
645}
646
647static gboolean bee_irc_channel_chat_topic( irc_channel_t *ic, const char *new )
648{
649        struct groupchat *c = ic->data;
650       
651        if( c == NULL )
652                return FALSE;
653       
654        if( c->ic->acc->prpl->chat_topic == NULL )
655                irc_send_num( ic->irc, 482, "%s :IM network does not support channel topics", ic->name );
656        else
657        {
658                /* TODO: Need more const goodness here, sigh */
659                char *topic = g_strdup( new );
660                c->ic->acc->prpl->chat_topic( c, topic );
661                g_free( topic );
662                return TRUE;
663        }
664               
665        return FALSE;
666}
667
668static gboolean bee_irc_channel_chat_invite( irc_channel_t *ic, irc_user_t *iu )
669{
670        struct groupchat *c = ic->data;
671        bee_user_t *bu = iu->bu;
672       
673        if( bu == NULL )
674                return FALSE;
675       
676        if( c )
677        {
678                if( iu->bu->ic != c->ic )
679                        irc_send_num( ic->irc, 482, "%s :Can't mix different IM networks in one groupchat", ic->name );
680                else if( c->ic->acc->prpl->chat_invite )
681                        c->ic->acc->prpl->chat_invite( c, iu->bu->handle, NULL );
682                else
683                        irc_send_num( ic->irc, 482, "%s :IM protocol does not support room invitations", ic->name );
684        }
685        else if( bu->ic->acc->prpl->chat_with &&
686                 strcmp( set_getstr( &ic->set, "chat_type" ), "groupchat" ) == 0 )
687        {
688                ic->flags |= IRC_CHANNEL_CHAT_PICKME;
689                iu->bu->ic->acc->prpl->chat_with( bu->ic, bu->handle );
690                ic->flags &= ~IRC_CHANNEL_CHAT_PICKME;
691        }
692        else
693        {
694                irc_send_num( ic->irc, 482, "%s :IM protocol does not support room invitations", ic->name );
695        }
696       
697        return TRUE;
698}
699
700static char *set_eval_room_account( set_t *set, char *value );
701static char *set_eval_chat_type( set_t *set, char *value );
702
703static gboolean bee_irc_channel_init( irc_channel_t *ic )
704{
705        set_add( &ic->set, "account", NULL, set_eval_room_account, ic );
706        set_add( &ic->set, "chat_type", "groupchat", set_eval_chat_type, ic );
707        set_add( &ic->set, "nick", NULL, NULL, ic );
708        set_add( &ic->set, "room", NULL, NULL, ic );
709       
710        /* chat_type == groupchat */
711        ic->flags |= IRC_CHANNEL_TEMP;
712       
713        return TRUE;
714}
715
716static char *set_eval_room_account( set_t *set, char *value )
717{
718        struct irc_channel *ic = set->data;
719        account_t *acc;
720       
721        if( !( acc = account_get( ic->irc->b, value ) ) )
722                return SET_INVALID;
723        else if( !acc->prpl->chat_join )
724        {
725                irc_usermsg( ic->irc, "Named chatrooms not supported on that account." );
726                return SET_INVALID;
727        }
728       
729        return g_strdup_printf( "%s(%s)", acc->prpl->name, acc->user );
730}
731
732static char *set_eval_chat_type( set_t *set, char *value )
733{
734        struct irc_channel *ic = set->data;
735       
736        if( strcmp( value, "groupchat" ) == 0 )
737                ic->flags |= IRC_CHANNEL_TEMP;
738        else if( strcmp( value, "room" ) == 0 )
739                ic->flags &= ~IRC_CHANNEL_TEMP;
740        else
741                return NULL;
742       
743        return value;
744}
745
746static gboolean bee_irc_channel_free( irc_channel_t *ic )
747{
748        set_del( &ic->set, "account" );
749        set_del( &ic->set, "chat_type" );
750        set_del( &ic->set, "nick" );
751        set_del( &ic->set, "room" );
752       
753        ic->flags &= ~IRC_CHANNEL_TEMP;
754       
755        return TRUE;
756}
757
758const struct irc_channel_funcs irc_channel_im_chat_funcs = {
759        bee_irc_channel_chat_privmsg,
760        bee_irc_channel_chat_join,
761        bee_irc_channel_chat_part,
762        bee_irc_channel_chat_topic,
763        bee_irc_channel_chat_invite,
764
765        bee_irc_channel_init,
766        bee_irc_channel_free,
767};
768
769
770/* IM->IRC: File transfers */
771static file_transfer_t *bee_irc_ft_in_start( bee_t *bee, bee_user_t *bu, const char *file_name, size_t file_size )
772{
773        return dccs_send_start( bu->ic, (irc_user_t *) bu->ui_data, file_name, file_size );
774}
775
776static gboolean bee_irc_ft_out_start( struct im_connection *ic, file_transfer_t *ft )
777{
778        return dccs_recv_start( ft );
779}
780
781static void bee_irc_ft_close( struct im_connection *ic, file_transfer_t *ft )
782{
783        return dcc_close( ft );
784}
785
786static void bee_irc_ft_finished( struct im_connection *ic, file_transfer_t *file )
787{
788        dcc_file_transfer_t *df = file->priv;
789
790        if( file->bytes_transferred >= file->file_size )
791                dcc_finish( file );
792        else
793                df->proto_finished = TRUE;
794}
795
796const struct bee_ui_funcs irc_ui_funcs = {
797        bee_irc_user_new,
798        bee_irc_user_free,
799        bee_irc_user_fullname,
800        bee_irc_user_nick_hint,
801        bee_irc_user_group,
802        bee_irc_user_status,
803        bee_irc_user_msg,
804        bee_irc_user_typing,
805       
806        bee_irc_chat_new,
807        bee_irc_chat_free,
808        bee_irc_chat_log,
809        bee_irc_chat_msg,
810        bee_irc_chat_add_user,
811        bee_irc_chat_remove_user,
812        bee_irc_chat_topic,
813        bee_irc_chat_name_hint,
814       
815        bee_irc_ft_in_start,
816        bee_irc_ft_out_start,
817        bee_irc_ft_close,
818        bee_irc_ft_finished,
819};
Note: See TracBrowser for help on using the repository browser.