source: irc_im.c @ 50b8978

Last change on this file since 50b8978 was f7ca587, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-29T18:18:54Z

Restore default_target setting, kill last_root_cmd variable and just use
the last_channel variable, like for any other user.

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