source: irc_im.c @ 2fe5eb9

Last change on this file since 2fe5eb9 was 2fe5eb9, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-29T17:08:16Z

Clean up references from irc_user structs to channels that are being free()d.

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