- persistente und vordefinierte Channels implementiert.
[ngircd-alex.git] / src / ngircd / irc-channel.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
4  *
5  * Dieses Programm ist freie Software. Sie koennen es unter den Bedingungen
6  * der GNU General Public License (GPL), wie von der Free Software Foundation
7  * herausgegeben, weitergeben und/oder modifizieren, entweder unter Version 2
8  * der Lizenz oder (wenn Sie es wuenschen) jeder spaeteren Version.
9  * Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
10  * der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
11  *
12  * $Id: irc-channel.c,v 1.5 2002/05/21 00:10:16 alex Exp $
13  *
14  * irc-channel.c: IRC-Channel-Befehle
15  */
16
17
18 #include "portab.h"
19
20 #include "imp.h"
21 #include <assert.h>
22 #include <string.h>
23
24 #include "defines.h"
25 #include "irc.h"
26 #include "irc-write.h"
27 #include "log.h"
28 #include "messages.h"
29
30 #include "exp.h"
31 #include "irc-channel.h"
32
33
34 GLOBAL BOOLEAN IRC_JOIN( CLIENT *Client, REQUEST *Req )
35 {
36         CHAR *channame, *flags, *topic, modes[8];
37         BOOLEAN is_new_chan;
38         CLIENT *target;
39         CHANNEL *chan;
40
41         assert( Client != NULL );
42         assert( Req != NULL );
43
44         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
45
46         /* Falsche Anzahl Parameter? */
47         if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
48
49         /* Wer ist der Absender? */
50         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix );
51         else target = Client;
52         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
53
54         /* Channel-Namen durchgehen */
55         channame = strtok( Req->argv[0], "," );
56         while( channame )
57         {
58                 /* wird der Channel neu angelegt? */
59                 flags = NULL;
60
61                 if( Channel_Search( channame )) is_new_chan = FALSE;
62                 else is_new_chan = TRUE;
63
64                 /* Hat ein Server Channel-User-Modes uebergeben? */
65                 if( Client_Type( Client ) == CLIENT_SERVER )
66                 {
67                         /* Channel-Flags extrahieren */
68                         flags = strchr( channame, 0x7 );
69                         if( flags ) *flags++ = '\0';
70                 }
71
72                 /* neuer Channel udn lokaler Client? */
73                 if( is_new_chan && ( Client_Type( Client ) == CLIENT_USER ))
74                 {
75                         /* Dann soll der Client Channel-Operator werden! */
76                         flags = "o";
77                 }
78
79                 /* Channel joinen (und ggf. anlegen) */
80                 if( ! Channel_Join( target, channame ))
81                 {
82                         /* naechsten Namen ermitteln */
83                         channame = strtok( NULL, "," );
84                         continue;
85                 }
86                 chan = Channel_Search( channame );
87                 assert( chan != NULL );
88
89                 /* Modes setzen (wenn vorhanden) */
90                 while( flags && *flags )
91                 {
92                         Channel_UserModeAdd( chan, target, *flags );
93                         flags++;
94                 }
95
96                 /* Wenn persistenter Channel und IRC-Operator: zum Channel-OP machen */
97                 if(( strchr( Channel_Modes( chan ), 'P' )) && ( strchr( Client_Modes( target ), 'o' ))) Channel_UserModeAdd( chan, target, 'o' );
98
99                 /* Muessen Modes an andere Server gemeldet werden? */
100                 strcpy( &modes[1], Channel_UserModes( chan, target ));
101                 if( modes[1] ) modes[0] = 0x7;
102                 else modes[0] = '\0';
103
104                 /* An andere Server weiterleiten */
105                 IRC_WriteStrServersPrefix( Client, target, "JOIN :%s%s", channame, modes );
106
107                 /* im Channel bekannt machen */
108                 IRC_WriteStrChannelPrefix( Client, chan, target, FALSE, "JOIN :%s", channame );
109                 if( modes[1] )
110                 {
111                         /* Modes im Channel bekannt machen */
112                         IRC_WriteStrChannelPrefix( Client, chan, target, FALSE, "MODE %s %s :%s", channame, modes, Client_ID( target ));
113                 }
114
115                 if( Client_Type( Client ) == CLIENT_USER )
116                 {
117                         /* an Client bestaetigen */
118                         IRC_WriteStrClientPrefix( Client, target, "JOIN :%s", channame );
119
120                         /* Topic an Client schicken */
121                         topic = Channel_Topic( chan );
122                         if( *topic ) IRC_WriteStrClient( Client, RPL_TOPIC_MSG, Client_ID( Client ), channame, topic );
123
124                         /* Mitglieder an Client Melden */
125                         IRC_Send_NAMES( Client, chan );
126                         IRC_WriteStrClient( Client, RPL_ENDOFNAMES_MSG, Client_ID( Client ), Channel_Name( chan ));
127                 }
128
129                 /* naechsten Namen ermitteln */
130                 channame = strtok( NULL, "," );
131         }
132         return CONNECTED;
133 } /* IRC_JOIN */
134
135
136 GLOBAL BOOLEAN IRC_PART( CLIENT *Client, REQUEST *Req )
137 {
138         CLIENT *target;
139         CHAR *chan;
140
141         assert( Client != NULL );
142         assert( Req != NULL );
143
144         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
145
146         /* Falsche Anzahl Parameter? */
147         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
148
149         /* Wer ist der Absender? */
150         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix );
151         else target = Client;
152         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
153
154         /* Channel-Namen durchgehen */
155         chan = strtok( Req->argv[0], "," );
156         while( chan )
157         {
158                 if( ! Channel_Part( target, Client, chan, Req->argc > 1 ? Req->argv[1] : Client_ID( target )))
159                 {
160                         /* naechsten Namen ermitteln */
161                         chan = strtok( NULL, "," );
162                         continue;
163                 }
164
165                 /* naechsten Namen ermitteln */
166                 chan = strtok( NULL, "," );
167         }
168         return CONNECTED;
169 } /* IRC_PART */
170
171
172 GLOBAL BOOLEAN IRC_TOPIC( CLIENT *Client, REQUEST *Req )
173 {
174         CHANNEL *chan;
175         CLIENT *from;
176         CHAR *topic;
177
178         assert( Client != NULL );
179         assert( Req != NULL );
180
181         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
182
183         /* Falsche Anzahl Parameter? */
184         if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
185
186         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
187         else from = Client;
188         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
189
190         /* Welcher Channel? */
191         chan = Channel_Search( Req->argv[0] );
192         if( ! chan ) return IRC_WriteStrClient( from, ERR_NOTONCHANNEL_MSG, Client_ID( from ), Req->argv[0] );
193
194         /* Ist der User Mitglied in dem Channel? */
195         if( ! Channel_IsMemberOf( chan, from )) return IRC_WriteStrClient( from, ERR_NOTONCHANNEL_MSG, Client_ID( from ), Req->argv[0] );
196
197         if( Req->argc == 1 )
198         {
199                 /* Topic erfragen */
200                 topic = Channel_Topic( chan );
201                 if( *topic ) return IRC_WriteStrClient( from, RPL_TOPIC_MSG, Client_ID( from ), Channel_Name( chan ), topic );
202                 else return IRC_WriteStrClient( from, RPL_NOTOPIC_MSG, Client_ID( from ), Channel_Name( chan ));
203         }
204
205         if( strchr( Channel_Modes( chan ), 't' ))
206         {
207                 /* Topic Lock. Ist der User ein Channel Operator? */
208                 if( ! strchr( Channel_UserModes( chan, from ), 'o' )) return IRC_WriteStrClient( from, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( from ), Channel_Name( chan ));
209         }
210
211         /* Topic setzen */
212         Channel_SetTopic( chan, Req->argv[1] );
213         Log( LOG_DEBUG, "User \"%s\" set topic on \"%s\": %s", Client_Mask( from ), Channel_Name( chan ), Req->argv[1][0] ? Req->argv[1] : "<none>" );
214
215         /* im Channel bekannt machen und an Server weiterleiten */
216         IRC_WriteStrServersPrefix( Client, from, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
217         IRC_WriteStrChannelPrefix( Client, chan, from, FALSE, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
218
219         if( Client_Type( Client ) == CLIENT_USER ) return IRC_WriteStrClientPrefix( Client, Client, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
220         else return CONNECTED;
221 } /* IRC_TOPIC */
222
223
224 GLOBAL BOOLEAN IRC_LIST( CLIENT *Client, REQUEST *Req )
225 {
226         CHAR *pattern;
227         CHANNEL *chan;
228
229         assert( Client != NULL );
230         assert( Req != NULL );
231
232         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
233
234         /* Falsche Anzahl Parameter? */
235         if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
236
237         if( Req->argc > 0 ) pattern = strtok( Req->argv[0], "," );
238         else pattern = "*";
239         
240         while( pattern )
241         {
242                 /* alle Channel durchgehen */
243                 chan = Channel_First( );
244                 while( chan )
245                 {
246                         /* Passt die Suchmaske auf diesen Channel? Bisher werden hier
247                          * "regular expressions" aber noch nicht unterstuetzt ... */
248                         if(( strcasecmp( pattern, Channel_Name( chan )) == 0 ) || ( strcmp( pattern, "*" ) == 0 ))
249                         {
250                                 /* Treffer! */
251                                 if( ! IRC_WriteStrClient( Client, RPL_LIST_MSG, Client_ID( Client), Channel_Name( chan ), Channel_MemberCount( chan ), Channel_Topic( chan ))) return DISCONNECTED;
252                         }
253                         chan = Channel_Next( chan );
254                 }
255                 
256                 /* naechsten Namen ermitteln */
257                 if( Req->argc > 0 ) pattern = strtok( NULL, "," );
258                 else pattern = NULL;
259         }
260         
261         return IRC_WriteStrClient( Client, RPL_LISTEND_MSG, Client_ID( Client ));
262 } /* IRC_LIST */
263
264
265 /* -eof- */