source: irc_channel.c @ 36577aa

Last change on this file since 36577aa was eb37735, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-05-08T23:54:37Z

This is how you now start groupchats: /join #channel, /invite people.

  • Property mode set to 100644
File size: 6.7 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 gint irc_channel_user_cmp( gconstpointer a_, gconstpointer b_ );
29static const struct irc_channel_funcs control_channel_funcs;
30static const struct irc_channel_funcs groupchat_stub_funcs;
31
32irc_channel_t *irc_channel_new( irc_t *irc, const char *name )
33{
34        irc_channel_t *ic;
35       
36        if( !irc_channel_name_ok( name ) || irc_channel_by_name( irc, name ) )
37                return NULL;
38       
39        ic = g_new0( irc_channel_t, 1 );
40        ic->irc = irc;
41        ic->name = g_strdup( name );
42        strcpy( ic->mode, CMODE );
43       
44        irc_channel_add_user( ic, irc->root );
45        if( strcmp( set_getstr( &irc->b->set, "ops" ), "both" ) == 0 ||
46            strcmp( set_getstr( &irc->b->set, "ops" ), "root" ) == 0 )
47                irc_channel_user_set_mode( ic, irc->root, IRC_CHANNEL_USER_OP );
48       
49        irc->channels = g_slist_prepend( irc->channels, ic );
50       
51        if( name[0] == '&' )
52                ic->f = &control_channel_funcs;
53        else /* if( name[0] == '#' ) */
54                ic->f = &groupchat_stub_funcs;
55       
56        return ic;
57}
58
59irc_channel_t *irc_channel_by_name( irc_t *irc, const char *name )
60{
61        GSList *l;
62       
63        for( l = irc->channels; l; l = l->next )
64        {
65                irc_channel_t *ic = l->data;
66               
67                if( name[0] == ic->name[0] && nick_cmp( name + 1, ic->name + 1 ) == 0 )
68                        return ic;
69        }
70       
71        return NULL;
72}
73
74int irc_channel_free( irc_channel_t *ic )
75{
76        irc_t *irc = ic->irc;
77       
78        if( ic->flags & IRC_CHANNEL_JOINED )
79                irc_channel_del_user( ic, irc->user );
80       
81        irc->channels = g_slist_remove( irc->channels, ic );
82        while( ic->users )
83        {
84                g_free( ic->users->data );
85                ic->users = g_slist_remove( ic->users, ic->users->data );
86        }
87       
88        g_free( ic->name );
89        g_free( ic->topic );
90        g_free( ic );
91       
92        return 1;
93}
94
95int irc_channel_add_user( irc_channel_t *ic, irc_user_t *iu )
96{
97        irc_channel_user_t *icu;
98       
99        if( irc_channel_has_user( ic, iu ) )
100                return 0;
101       
102        icu = g_new0( irc_channel_user_t, 1 );
103        icu->iu = iu;
104       
105        ic->users = g_slist_insert_sorted( ic->users, icu, irc_channel_user_cmp );
106       
107        if( iu == ic->irc->user || ic->flags & IRC_CHANNEL_JOINED )
108        {
109                ic->flags |= IRC_CHANNEL_JOINED;
110                irc_send_join( ic, iu );
111        }
112       
113        return 1;
114}
115
116int irc_channel_del_user( irc_channel_t *ic, irc_user_t *iu )
117{
118        irc_channel_user_t *icu;
119       
120        if( !( icu = irc_channel_has_user( ic, iu ) ) )
121                return 0;
122       
123        ic->users = g_slist_remove( ic->users, icu );
124        g_free( icu );
125       
126        if( ic->flags & IRC_CHANNEL_JOINED )
127                irc_send_part( ic, iu, "" );
128       
129        if( iu == ic->irc->user )
130        {
131                ic->flags &= ~IRC_CHANNEL_JOINED;
132                if( ic->f->part )
133                        ic->f->part( ic, NULL );
134        }
135       
136        return 1;
137}
138
139irc_channel_user_t *irc_channel_has_user( irc_channel_t *ic, irc_user_t *iu )
140{
141        GSList *l;
142       
143        for( l = ic->users; l; l = l->next )
144        {
145                irc_channel_user_t *icu = l->data;
146               
147                if( icu->iu == iu )
148                        return icu;
149        }
150       
151        return NULL;
152}
153
154int irc_channel_set_topic( irc_channel_t *ic, const char *topic, const irc_user_t *iu )
155{
156        g_free( ic->topic );
157        ic->topic = g_strdup( topic );
158       
159        g_free( ic->topic_who );
160        if( iu )
161                ic->topic_who = g_strdup_printf( "%s!%s@%s", iu->nick, iu->user, iu->host );
162        else
163                ic->topic_who = NULL;
164       
165        ic->topic_time = time( NULL );
166       
167        if( ic->flags & IRC_CHANNEL_JOINED )
168                irc_send_topic( ic, TRUE );
169       
170        return 1;
171}
172
173void irc_channel_user_set_mode( irc_channel_t *ic, irc_user_t *iu, irc_channel_user_flags_t flags )
174{
175        irc_channel_user_t *icu = irc_channel_has_user( ic, iu );
176       
177        if( icu->flags == flags )
178                return;
179       
180        if( ic->flags & IRC_CHANNEL_JOINED )
181                irc_send_channel_user_mode_diff( ic, iu, icu->flags, flags );
182       
183        icu->flags = flags;
184}
185
186void irc_channel_printf( irc_channel_t *ic, char *format, ... )
187{
188        va_list params;
189        char *text;
190       
191        va_start( params, format );
192        text = g_strdup_vprintf( format, params );
193        va_end( params );
194       
195        irc_send_msg( ic->irc->root, "PRIVMSG", ic->name, text, NULL );
196        g_free( text );
197}
198
199gboolean irc_channel_name_ok( const char *name )
200{
201        return strchr( CTYPES, name[0] ) != NULL && nick_ok( name + 1 );
202}
203
204static gint irc_channel_user_cmp( gconstpointer a_, gconstpointer b_ )
205{
206        const irc_channel_user_t *a = a_, *b = b_;
207       
208        return irc_user_cmp( a->iu, b->iu );
209}
210
211/* Channel-type dependent functions, for control channels: */
212static gboolean control_channel_privmsg( irc_channel_t *ic, const char *msg )
213{
214        irc_t *irc = ic->irc;
215        const char *s;
216       
217        /* Scan for non-whitespace chars followed by a colon: */
218        for( s = msg; *s && !isspace( *s ) && *s != ':' && *s != ','; s ++ ) {}
219       
220        if( *s == ':' || *s == ',' )
221        {
222                char to[s-msg+1];
223                irc_user_t *iu;
224               
225                memset( to, 0, sizeof( to ) );
226                strncpy( to, msg, s - msg );
227                while( *(++s) && isspace( *s ) ) {}
228               
229                iu = irc_user_by_name( irc, to );
230                if( iu && iu->f->privmsg )
231                {
232                        iu->flags &= ~IRC_USER_PRIVATE;
233                        iu->f->privmsg( iu, s );
234                }
235                else
236                {
237                        irc_channel_printf( ic, "User does not exist: %s", to );
238                }
239        }
240        else
241        {
242                /* TODO: Maybe just use root->privmsg here now? */
243                char cmd[strlen(msg)+1];
244               
245                g_free( ic->irc->last_root_cmd );
246                ic->irc->last_root_cmd = g_strdup( ic->name );
247               
248                strcpy( cmd, msg );
249                root_command_string( ic->irc, cmd );
250        }
251       
252        return TRUE;
253}
254
255static const struct irc_channel_funcs control_channel_funcs = {
256        control_channel_privmsg,
257};
258
259/* Groupchat stub: Only handles /INVITE at least for now. */
260static gboolean groupchat_stub_invite( irc_channel_t *ic, irc_user_t *iu )
261{
262        bee_user_t *bu = iu->bu;
263       
264        if( iu->bu->ic->acc->prpl->chat_with )
265        {
266                ic->flags |= IRC_CHANNEL_CHAT_PICKME;
267                iu->bu->ic->acc->prpl->chat_with( bu->ic, bu->handle );
268                ic->flags &= ~IRC_CHANNEL_CHAT_PICKME;
269                return TRUE;
270        }
271        else
272        {
273                irc_send_num( ic->irc, 482, "%s :IM protocol does not support room invitations", ic->name );
274                return FALSE;
275        }
276}
277
278static const struct irc_channel_funcs groupchat_stub_funcs = {
279        NULL,
280        NULL,
281        NULL,
282        NULL,
283        groupchat_stub_invite,
284};
Note: See TracBrowser for help on using the repository browser.