source: irc_im.c @ db2cef1

Last change on this file since db2cef1 was badd148, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-12T23:22:53Z

Reformat nicks whenever fullname/nick/group changes (but at least for now
still only for offline users).

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