source: irc_channel.c @ 68adaf8

Last change on this file since 68adaf8 was bb151f7, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-11-20T20:25:44Z

Added irc_channel_with_user() function to find a suitable channel to show
a user's message in, instead of just &bitlbee by default.

  • Property mode set to 100644
File size: 19.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/* The IRC-based UI - Representing (virtual) channels.                  */
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
28static char *set_eval_channel_type( set_t *set, char *value );
29static gint irc_channel_user_cmp( gconstpointer a_, gconstpointer b_ );
30static const struct irc_channel_funcs control_channel_funcs;
31
32extern const struct irc_channel_funcs irc_channel_im_chat_funcs;
33
34irc_channel_t *irc_channel_new( irc_t *irc, const char *name )
35{
36        irc_channel_t *ic;
37       
38        if( !irc_channel_name_ok( name ) || irc_channel_by_name( irc, name ) )
39                return NULL;
40       
41        ic = g_new0( irc_channel_t, 1 );
42        ic->irc = irc;
43        ic->name = g_strdup( name );
44        strcpy( ic->mode, CMODE );
45       
46        irc_channel_add_user( ic, irc->root );
47       
48        irc->channels = g_slist_append( irc->channels, ic );
49       
50        set_add( &ic->set, "auto_join", "false", set_eval_bool, ic );
51        set_add( &ic->set, "type", "control", set_eval_channel_type, ic );
52       
53        if( name[0] == '&' )
54                set_setstr( &ic->set, "type", "control" );
55        else /* if( name[0] == '#' ) */
56                set_setstr( &ic->set, "type", "chat" );
57       
58        return ic;
59}
60
61irc_channel_t *irc_channel_by_name( irc_t *irc, const char *name )
62{
63        GSList *l;
64       
65        for( l = irc->channels; l; l = l->next )
66        {
67                irc_channel_t *ic = l->data;
68               
69                if( irc_channel_name_cmp( name, ic->name ) == 0 )
70                        return ic;
71        }
72       
73        return NULL;
74}
75
76irc_channel_t *irc_channel_get( irc_t *irc, char *id )
77{
78        irc_channel_t *ic, *ret = NULL;
79        GSList *l;
80        int nr;
81       
82        if( sscanf( id, "%d", &nr ) == 1 && nr < 1000 )
83        {
84                for( l = irc->channels; l; l = l->next )
85                {
86                        ic = l->data;
87                        if( ( nr-- ) == 0 ) 
88                                return ic;
89                }
90               
91                return NULL;
92        }
93       
94        /* Exact match first: Partial match only sucks if there's a channel
95           #aa and #aabb */
96        if( ( ret = irc_channel_by_name( irc, id ) ) )
97                return ret;
98       
99        for( l = irc->channels; l; l = l->next )
100        {
101                ic = l->data;
102               
103                if( strstr( ic->name, id ) )
104                {
105                        /* Make sure it's a unique match. */
106                        if( !ret )
107                                ret = ic;
108                        else
109                                return NULL;
110                }
111        }
112       
113        return ret;
114}
115
116int irc_channel_free( irc_channel_t *ic )
117{
118        irc_t *irc = ic->irc;
119        GSList *l;
120       
121        if( ic->flags & IRC_CHANNEL_JOINED )
122                irc_channel_del_user( ic, irc->user, IRC_CDU_KICK, "Cleaning up channel" );
123       
124        if( ic->f->_free )
125                ic->f->_free( ic );
126       
127        while( ic->set )
128                set_del( &ic->set, ic->set->key );
129       
130        irc->channels = g_slist_remove( irc->channels, ic );
131        while( ic->users )
132        {
133                g_free( ic->users->data );
134                ic->users = g_slist_remove( ic->users, ic->users->data );
135        }
136       
137        for( l = irc->users; l; l = l->next )
138        {
139                irc_user_t *iu = l->data;
140               
141                if( iu->last_channel == ic )
142                        iu->last_channel = irc->default_channel;
143        }
144       
145        g_free( ic->name );
146        g_free( ic->topic );
147        g_free( ic->topic_who );
148        g_free( ic );
149       
150        return 1;
151}
152
153struct irc_channel_free_data
154{
155        irc_t *irc;
156        irc_channel_t *ic;
157        char *name;
158};
159
160static gboolean irc_channel_free_callback( gpointer data, gint fd, b_input_condition cond )
161{
162        struct irc_channel_free_data *d = data;
163       
164        if( g_slist_find( irc_connection_list, d->irc ) &&
165            irc_channel_by_name( d->irc, d->name ) == d->ic &&
166            !( d->ic->flags & IRC_CHANNEL_JOINED ) )
167                irc_channel_free( d->ic );
168
169        g_free( d->name );
170        g_free( d );
171        return FALSE;
172}
173
174/* Free the channel, but via the event loop, so after finishing whatever event
175   we're currently handling. */
176void irc_channel_free_soon( irc_channel_t *ic )
177{
178        struct irc_channel_free_data *d = g_new0( struct irc_channel_free_data, 1 );
179       
180        d->irc = ic->irc;
181        d->ic = ic;
182        d->name = g_strdup( ic->name );
183       
184        b_timeout_add( 0, irc_channel_free_callback, d );
185}
186
187static char *set_eval_channel_type( set_t *set, char *value )
188{
189        struct irc_channel *ic = set->data;
190        const struct irc_channel_funcs *new;
191       
192        if( strcmp( value, "control" ) == 0 )
193                new = &control_channel_funcs;
194        else if( ic != ic->irc->default_channel && strcmp( value, "chat" ) == 0 )
195                new = &irc_channel_im_chat_funcs;
196        else
197                return SET_INVALID;
198       
199        /* TODO: Return values. */
200        if( ic->f && ic->f->_free )
201                ic->f->_free( ic );
202       
203        ic->f = new;
204       
205        if( ic->f && ic->f->_init )
206                ic->f->_init( ic );
207       
208        return value;
209}
210
211int irc_channel_add_user( irc_channel_t *ic, irc_user_t *iu )
212{
213        irc_channel_user_t *icu;
214       
215        if( irc_channel_has_user( ic, iu ) )
216                return 0;
217       
218        icu = g_new0( irc_channel_user_t, 1 );
219        icu->iu = iu;
220       
221        ic->users = g_slist_insert_sorted( ic->users, icu, irc_channel_user_cmp );
222       
223        irc_channel_update_ops( ic, set_getstr( &ic->irc->b->set, "ops" ) );
224       
225        if( iu == ic->irc->user || ic->flags & IRC_CHANNEL_JOINED )
226        {
227                ic->flags |= IRC_CHANNEL_JOINED;
228                irc_send_join( ic, iu );
229        }
230       
231        return 1;
232}
233
234int irc_channel_del_user( irc_channel_t *ic, irc_user_t *iu, irc_channel_del_user_type_t type, const char *msg )
235{
236        irc_channel_user_t *icu;
237       
238        if( !( icu = irc_channel_has_user( ic, iu ) ) )
239                return 0;
240       
241        ic->users = g_slist_remove( ic->users, icu );
242        g_free( icu );
243       
244        if( !( ic->flags & IRC_CHANNEL_JOINED ) || type == IRC_CDU_SILENT ) {}
245                /* Do nothing. The caller should promise it won't screw
246                   up state of the IRC client. :-) */
247        else if( type == IRC_CDU_PART )
248                irc_send_part( ic, iu, msg );
249        else if( type == IRC_CDU_KICK )
250                irc_send_kick( ic, iu, ic->irc->root, msg );
251       
252        if( iu == ic->irc->user )
253        {
254                ic->flags &= ~IRC_CHANNEL_JOINED;
255               
256                if( ic->irc->status & USTATUS_SHUTDOWN )
257                {
258                        /* Don't do anything fancy when we're shutting down anyway. */
259                }
260                else if( ic->flags & IRC_CHANNEL_TEMP )
261                {
262                        irc_channel_free_soon( ic );
263                }
264                else
265                {
266                        /* Flush userlist now. The user won't see it anyway. */
267                        while( ic->users )
268                        {
269                                g_free( ic->users->data );
270                                ic->users = g_slist_remove( ic->users, ic->users->data );
271                        }
272                        irc_channel_add_user( ic, ic->irc->root );
273                }
274        }
275       
276        return 1;
277}
278
279irc_channel_user_t *irc_channel_has_user( irc_channel_t *ic, irc_user_t *iu )
280{
281        GSList *l;
282       
283        for( l = ic->users; l; l = l->next )
284        {
285                irc_channel_user_t *icu = l->data;
286               
287                if( icu->iu == iu )
288                        return icu;
289        }
290       
291        return NULL;
292}
293
294/* Find a channel we're currently in, that currently has iu in it. */
295struct irc_channel *irc_channel_with_user( irc_t *irc, irc_user_t *iu )
296{
297        GSList *l;
298       
299        for( l = irc->channels; l; l = l->next )
300        {
301                irc_channel_t *ic = l->data;
302               
303                if( strcmp( set_getstr( &ic->set, "type" ), "control" ) != 0 )
304                        continue;
305               
306                if( ( ic->flags & IRC_CHANNEL_JOINED ) &&
307                    irc_channel_has_user( ic, iu ) )
308                        return ic;
309        }
310       
311        /* If there was no match, try once more but just see if the user
312           *would* be in the channel, i.e. if s/he were online. */
313        if( iu->bu == NULL )
314                return NULL;
315       
316        for( l = irc->channels; l; l = l->next )
317        {
318                irc_channel_t *ic = l->data;
319               
320                if( strcmp( set_getstr( &ic->set, "type" ), "control" ) != 0 )
321                        continue;
322               
323                if( ( ic->flags & IRC_CHANNEL_JOINED ) &&
324                    irc_channel_wants_user( ic, iu ) )
325                        return ic;
326        }
327       
328        return NULL;
329}
330
331int irc_channel_set_topic( irc_channel_t *ic, const char *topic, const irc_user_t *iu )
332{
333        g_free( ic->topic );
334        ic->topic = g_strdup( topic );
335       
336        g_free( ic->topic_who );
337        if( iu )
338                ic->topic_who = g_strdup_printf( "%s!%s@%s", iu->nick, iu->user, iu->host );
339        else
340                ic->topic_who = NULL;
341       
342        ic->topic_time = time( NULL );
343       
344        if( ic->flags & IRC_CHANNEL_JOINED )
345                irc_send_topic( ic, TRUE );
346       
347        return 1;
348}
349
350void irc_channel_user_set_mode( irc_channel_t *ic, irc_user_t *iu, irc_channel_user_flags_t flags )
351{
352        irc_channel_user_t *icu = irc_channel_has_user( ic, iu );
353       
354        if( !icu || icu->flags == flags )
355                return;
356       
357        if( ic->flags & IRC_CHANNEL_JOINED )
358                irc_send_channel_user_mode_diff( ic, iu, icu->flags, flags );
359       
360        icu->flags = flags;
361}
362
363void irc_channel_set_mode( irc_channel_t *ic, const char *s )
364{
365        irc_t *irc = ic->irc;
366        char m[128], st = 1;
367        const char *t;
368        int i;
369        char changes[512], *p, st2 = 2;
370       
371        memset( m, 0, sizeof( m ) );
372       
373        for( t = ic->mode; *t; t ++ )
374                if( *t < sizeof( m ) )
375                        m[(int)*t] = 1;
376       
377        p = changes;
378        for( t = s; *t; t ++ )
379        {
380                if( *t == '+' || *t == '-' )
381                        st = *t == '+';
382                else if( strchr( CMODES, *t ) )
383                {
384                        if( m[(int)*t] != st)
385                        {
386                                if( st != st2 )
387                                        st2 = st, *p++ = st ? '+' : '-';
388                                *p++ = *t;
389                        }
390                        m[(int)*t] = st;
391                }
392        }
393        *p = '\0';
394       
395        memset( ic->mode, 0, sizeof( ic->mode ) );
396       
397        for( i = 'A'; i <= 'z' && strlen( ic->mode ) < ( sizeof( ic->mode ) - 1 ); i ++ )
398                if( m[i] )
399                        ic->mode[strlen(ic->mode)] = i;
400       
401        if( *changes && ( ic->flags & IRC_CHANNEL_JOINED ) )
402                irc_write( irc, ":%s!%s@%s MODE %s :%s", irc->root->nick,
403                           irc->root->user, irc->root->host, ic->name,
404                           changes );
405}
406
407void irc_channel_auto_joins( irc_t *irc, account_t *acc )
408{
409        GSList *l;
410       
411        for( l = irc->channels; l; l = l->next )
412        {
413                irc_channel_t *ic = l->data;
414                gboolean aj = set_getbool( &ic->set, "auto_join" );
415                char *type;
416               
417                if( acc &&
418                    ( type = set_getstr( &ic->set, "chat_type" ) ) &&
419                    strcmp( type, "room" ) == 0 )
420                {
421                        /* Bit of an ugly special case: Handle chatrooms here, we
422                           can only auto-join them if their account is online. */
423                        char *acc_s;
424                       
425                        if( !aj && !( ic->flags & IRC_CHANNEL_JOINED ) )
426                                /* Only continue if this one's marked as auto_join
427                                   or if we're in it already. (Possible if the
428                                   client auto-rejoined it before identyfing.) */
429                                continue;
430                        else if( !( acc_s = set_getstr( &ic->set, "account" ) ) )
431                                continue;
432                        else if( account_get( irc->b, acc_s ) != acc )
433                                continue;
434                        else if( acc->ic == NULL || !( acc->ic->flags & OPT_LOGGED_IN ) )
435                                continue;
436                        else
437                                ic->f->join( ic );
438                }
439                else if( aj )
440                {
441                        irc_channel_add_user( ic, irc->user );
442                }
443        }
444}
445
446void irc_channel_printf( irc_channel_t *ic, char *format, ... )
447{
448        va_list params;
449        char *text;
450       
451        va_start( params, format );
452        text = g_strdup_vprintf( format, params );
453        va_end( params );
454       
455        irc_send_msg( ic->irc->root, "PRIVMSG", ic->name, text, NULL );
456        g_free( text );
457}
458
459gboolean irc_channel_name_ok( const char *name_ )
460{
461        const unsigned char *name = (unsigned char*) name_;
462        int i;
463       
464        if( name_[0] == '\0' )
465                return FALSE;
466       
467        /* Check if the first character is in CTYPES (#&) */
468        if( strchr( CTYPES, name_[0] ) == NULL )
469                return FALSE;
470       
471        /* RFC 1459 keeps amazing me: While only a "few" chars are allowed
472           in nicknames, channel names can be pretty much anything as long
473           as they start with # or &. I'll be a little bit more strict and
474           disallow all non-printable characters. */
475        for( i = 1; name[i]; i ++ )
476                if( name[i] <= ' ' || name[i] == ',' )
477                        return FALSE;
478       
479        return TRUE;
480}
481
482void irc_channel_name_strip( char *name )
483{
484        int i, j;
485       
486        for( i = j = 0; name[i]; i ++ )
487                if( name[i] > ' ' && name[i] != ',' )
488                        name[j++] = name[i];
489       
490        name[j] = '\0';
491}
492
493int irc_channel_name_cmp( const char *a_, const char *b_ )
494{
495        static unsigned char case_map[256];
496        const unsigned char *a = (unsigned char*) a_, *b = (unsigned char*) b_;
497        int i;
498       
499        if( case_map['A'] == '\0' )
500        {
501                for( i = 33; i < 256; i ++ )
502                        if( i != ',' )
503                                case_map[i] = i;
504               
505                for( i = 0; i < 26; i ++ )
506                        case_map['A'+i] = 'a' + i;
507               
508                case_map['['] = '{';
509                case_map[']'] = '}';
510                case_map['~'] = '`';
511                case_map['\\'] = '|';
512        }
513       
514        if( !irc_channel_name_ok( a_ ) || !irc_channel_name_ok( b_ ) )
515                return -1;
516       
517        for( i = 0; a[i] && b[i] && case_map[a[i]] && case_map[b[i]]; i ++ )
518        {
519                if( case_map[a[i]] == case_map[b[i]] )
520                        continue;
521                else
522                        return case_map[a[i]] - case_map[b[i]];
523        }
524       
525        return case_map[a[i]] - case_map[b[i]];
526}
527
528static gint irc_channel_user_cmp( gconstpointer a_, gconstpointer b_ )
529{
530        const irc_channel_user_t *a = a_, *b = b_;
531       
532        return irc_user_cmp( a->iu, b->iu );
533}
534
535void irc_channel_update_ops( irc_channel_t *ic, char *value )
536{
537        irc_channel_user_set_mode( ic, ic->irc->root,
538                ( strcmp( value, "both" ) == 0 ||
539                  strcmp( value, "root" ) == 0 ) ? IRC_CHANNEL_USER_OP : 0 );
540        irc_channel_user_set_mode( ic, ic->irc->user,
541                ( strcmp( value, "both" ) == 0 ||
542                  strcmp( value, "user" ) == 0 ) ? IRC_CHANNEL_USER_OP : 0 );
543}
544
545char *set_eval_irc_channel_ops( set_t *set, char *value )
546{
547        irc_t *irc = set->data;
548        GSList *l;
549       
550        if( strcmp( value, "both" ) != 0 && strcmp( value, "none" ) != 0 && 
551            strcmp( value, "user" ) != 0 && strcmp( value, "root" ) != 0 )
552                return SET_INVALID;
553       
554        for( l = irc->channels; l; l = l->next )
555                irc_channel_update_ops( l->data, value );
556       
557        return value;
558}
559
560/* Channel-type dependent functions, for control channels: */
561static gboolean control_channel_privmsg( irc_channel_t *ic, const char *msg )
562{
563        irc_t *irc = ic->irc;
564        irc_user_t *iu;
565        const char *s;
566       
567        /* Scan for non-whitespace chars followed by a colon: */
568        for( s = msg; *s && !isspace( *s ) && *s != ':' && *s != ','; s ++ ) {}
569       
570        if( *s == ':' || *s == ',' )
571        {
572                char to[s-msg+1];
573               
574                memset( to, 0, sizeof( to ) );
575                strncpy( to, msg, s - msg );
576                while( *(++s) && isspace( *s ) ) {}
577                msg = s;
578               
579                if( !( iu = irc_user_by_name( irc, to ) ) )
580                        irc_channel_printf( ic, "User does not exist: %s", to );
581                else
582                        ic->last_target = iu;
583        }
584        else if( g_strcasecmp( set_getstr( &irc->b->set, "default_target" ), "last" ) == 0 &&
585                 ic->last_target && g_slist_find( irc->users, ic->last_target ) )
586                iu = ic->last_target;
587        else
588                iu = irc->root;
589       
590        if( iu && iu->f->privmsg )
591        {
592                iu->last_channel = ic;
593                iu->f->privmsg( iu, msg );
594        }
595       
596        return TRUE;
597}
598
599static gboolean control_channel_invite( irc_channel_t *ic, irc_user_t *iu )
600{
601        struct irc_control_channel *icc = ic->data;
602        bee_user_t *bu = iu->bu;
603       
604        if( bu == NULL )
605                return FALSE;
606       
607        if( icc->type != IRC_CC_TYPE_GROUP )
608        {
609                irc_send_num( ic->irc, 482, "%s :Invitations are only possible to fill_by=group channels", ic->name );
610                return FALSE;
611        }
612       
613        bu->ic->acc->prpl->add_buddy( bu->ic, bu->handle,
614                                      icc->group ? icc->group->name : NULL );
615       
616        return TRUE;
617}
618
619static char *set_eval_by_account( set_t *set, char *value );
620static char *set_eval_fill_by( set_t *set, char *value );
621static char *set_eval_by_group( set_t *set, char *value );
622static char *set_eval_by_protocol( set_t *set, char *value );
623static char *set_eval_show_users( set_t *set, char *value );
624
625static gboolean control_channel_init( irc_channel_t *ic )
626{
627        struct irc_control_channel *icc;
628       
629        set_add( &ic->set, "account", NULL, set_eval_by_account, ic );
630        set_add( &ic->set, "fill_by", "all", set_eval_fill_by, ic );
631        set_add( &ic->set, "group", NULL, set_eval_by_group, ic );
632        set_add( &ic->set, "protocol", NULL, set_eval_by_protocol, ic );
633       
634        /* When changing the default, also change it below. */
635        set_add( &ic->set, "show_users", "online+,away", set_eval_show_users, ic );
636       
637        ic->data = icc = g_new0( struct irc_control_channel, 1 );
638        icc->type = IRC_CC_TYPE_DEFAULT;
639       
640        /* Have to run the evaluator to initialize icc->modes. */
641        set_setstr( &ic->set, "show_users", "online+,away" );
642       
643        /* For scripts that care. */
644        irc_channel_set_mode( ic, "+C" );
645       
646        return TRUE;
647}
648
649static gboolean control_channel_join( irc_channel_t *ic )
650{
651        bee_irc_channel_update( ic->irc, ic, NULL );
652       
653        return TRUE;
654}
655
656static char *set_eval_by_account( set_t *set, char *value )
657{
658        struct irc_channel *ic = set->data;
659        struct irc_control_channel *icc = ic->data;
660        account_t *acc;
661       
662        if( !( acc = account_get( ic->irc->b, value ) ) )
663                return SET_INVALID;
664       
665        icc->account = acc;
666        if( icc->type == IRC_CC_TYPE_ACCOUNT )
667                bee_irc_channel_update( ic->irc, ic, NULL );
668       
669        return g_strdup( acc->tag );
670}
671
672static char *set_eval_fill_by( set_t *set, char *value )
673{
674        struct irc_channel *ic = set->data;
675        struct irc_control_channel *icc = ic->data;
676       
677        if( strcmp( value, "all" ) == 0 )
678                icc->type = IRC_CC_TYPE_DEFAULT;
679        else if( strcmp( value, "rest" ) == 0 )
680                icc->type = IRC_CC_TYPE_REST;
681        else if( strcmp( value, "group" ) == 0 )
682                icc->type = IRC_CC_TYPE_GROUP;
683        else if( strcmp( value, "account" ) == 0 )
684                icc->type = IRC_CC_TYPE_ACCOUNT;
685        else if( strcmp( value, "protocol" ) == 0 )
686                icc->type = IRC_CC_TYPE_PROTOCOL;
687        else
688                return SET_INVALID;
689       
690        bee_irc_channel_update( ic->irc, ic, NULL );
691        return value;
692}
693
694static char *set_eval_by_group( set_t *set, char *value )
695{
696        struct irc_channel *ic = set->data;
697        struct irc_control_channel *icc = ic->data;
698       
699        icc->group = bee_group_by_name( ic->irc->b, value, TRUE );
700        if( icc->type == IRC_CC_TYPE_GROUP )
701                bee_irc_channel_update( ic->irc, ic, NULL );
702       
703        return g_strdup( icc->group->name );
704}
705
706static char *set_eval_by_protocol( set_t *set, char *value )
707{
708        struct irc_channel *ic = set->data;
709        struct irc_control_channel *icc = ic->data;
710        struct prpl *prpl;
711       
712        if( !( prpl = find_protocol( value ) ) )
713                return SET_INVALID;
714       
715        icc->protocol = prpl;
716        if( icc->type == IRC_CC_TYPE_PROTOCOL )
717                bee_irc_channel_update( ic->irc, ic, NULL );
718       
719        return value;
720}
721
722static char *set_eval_show_users( set_t *set, char *value )
723{
724        struct irc_channel *ic = set->data;
725        struct irc_control_channel *icc = ic->data;
726        char **parts = g_strsplit( value, ",", 0 ), **part;
727        char modes[4];
728       
729        memset( modes, 0, 4 );
730        for( part = parts; *part; part ++ )
731        {
732                char last, modechar = IRC_CHANNEL_USER_NONE;
733               
734                if( **part == '\0' )
735                        goto fail;
736               
737                last = (*part)[strlen(*part+1)];
738                if( last == '+' )
739                        modechar = IRC_CHANNEL_USER_VOICE;
740                else if( last == '%' )
741                        modechar = IRC_CHANNEL_USER_HALFOP;
742                else if( last == '@' )
743                        modechar = IRC_CHANNEL_USER_OP;
744               
745                if( strncmp( *part, "offline", 7 ) == 0 )
746                        modes[0] = modechar;
747                else if( strncmp( *part, "away", 4 ) == 0 )
748                        modes[1] = modechar;
749                else if( strncmp( *part, "online", 6 ) == 0 )
750                        modes[2] = modechar;
751                else
752                        goto fail;
753        }
754        memcpy( icc->modes, modes, 4 );
755        bee_irc_channel_update( ic->irc, ic, NULL );
756       
757        g_strfreev( parts );
758        return value;
759       
760fail:
761        g_strfreev( parts );
762        return SET_INVALID;     
763}
764
765/* Figure out if a channel is supposed to have the user, assuming s/he is
766   online or otherwise also selected by the show_users setting. Only works
767   for control channels, but does *not* check if this channel is of that
768   type. Beware! */
769gboolean irc_channel_wants_user( irc_channel_t *ic, irc_user_t *iu )
770{
771        struct irc_control_channel *icc = ic->data;
772       
773        if( iu->bu == NULL )
774                return FALSE;
775       
776        switch( icc->type )
777        {
778        case IRC_CC_TYPE_GROUP:
779                return iu->bu->group == icc->group;
780        case IRC_CC_TYPE_ACCOUNT:
781                return iu->bu->ic->acc == icc->account;
782        case IRC_CC_TYPE_PROTOCOL:
783                return iu->bu->ic->acc->prpl == icc->protocol;
784        case IRC_CC_TYPE_DEFAULT:
785        default:
786                return TRUE;
787        }
788}
789
790static gboolean control_channel_free( irc_channel_t *ic )
791{
792        struct irc_control_channel *icc = ic->data;
793       
794        set_del( &ic->set, "account" );
795        set_del( &ic->set, "fill_by" );
796        set_del( &ic->set, "group" );
797        set_del( &ic->set, "protocol" );
798        set_del( &ic->set, "show_users" );
799       
800        g_free( icc );
801        ic->data = NULL;
802       
803        /* For scripts that care. */
804        irc_channel_set_mode( ic, "-C" );
805       
806        return TRUE;
807}
808
809static const struct irc_channel_funcs control_channel_funcs = {
810        control_channel_privmsg,
811        control_channel_join,
812        NULL,
813        NULL,
814        control_channel_invite,
815       
816        control_channel_init,
817        control_channel_free,
818};
Note: See TracBrowser for help on using the repository browser.