source: irc_channel.c @ 4bc66ae

Last change on this file since 4bc66ae was cc20520, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-12-02T12:14:09Z

Clean up pastebuf_timer when cleaning up channels, and properly clean up
channel-chatroom reference when leaving a chatroom. This fixes two very
similar crash bugs when leaving a chatroom within the paste_buffer_delay
period.

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