79ccdd9adeaf299e3d0d073f60b08e100125d339
[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.4 2002/04/23 19:51:14 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                 /* Muessen Modes an andere Server gemeldet werden? */
97                 strcpy( &modes[1], Channel_UserModes( chan, target ));
98                 if( modes[1] ) modes[0] = 0x7;
99                 else modes[0] = '\0';
100
101                 /* An andere Server weiterleiten */
102                 IRC_WriteStrServersPrefix( Client, target, "JOIN :%s%s", channame, modes );
103
104                 /* im Channel bekannt machen */
105                 IRC_WriteStrChannelPrefix( Client, chan, target, FALSE, "JOIN :%s", channame );
106                 if( modes[1] )
107                 {
108                         /* Modes im Channel bekannt machen */
109                         IRC_WriteStrChannelPrefix( Client, chan, target, FALSE, "MODE %s %s :%s", channame, modes, Client_ID( target ));
110                 }
111
112                 if( Client_Type( Client ) == CLIENT_USER )
113                 {
114                         /* an Client bestaetigen */
115                         IRC_WriteStrClientPrefix( Client, target, "JOIN :%s", channame );
116
117                         /* Topic an Client schicken */
118                         topic = Channel_Topic( chan );
119                         if( *topic ) IRC_WriteStrClient( Client, RPL_TOPIC_MSG, Client_ID( Client ), channame, topic );
120
121                         /* Mitglieder an Client Melden */
122                         IRC_Send_NAMES( Client, chan );
123                         IRC_WriteStrClient( Client, RPL_ENDOFNAMES_MSG, Client_ID( Client ), Channel_Name( chan ));
124                 }
125
126                 /* naechsten Namen ermitteln */
127                 channame = strtok( NULL, "," );
128         }
129         return CONNECTED;
130 } /* IRC_JOIN */
131
132
133 GLOBAL BOOLEAN IRC_PART( CLIENT *Client, REQUEST *Req )
134 {
135         CLIENT *target;
136         CHAR *chan;
137
138         assert( Client != NULL );
139         assert( Req != NULL );
140
141         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
142
143         /* Falsche Anzahl Parameter? */
144         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
145
146         /* Wer ist der Absender? */
147         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix );
148         else target = Client;
149         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
150
151         /* Channel-Namen durchgehen */
152         chan = strtok( Req->argv[0], "," );
153         while( chan )
154         {
155                 if( ! Channel_Part( target, Client, chan, Req->argc > 1 ? Req->argv[1] : Client_ID( target )))
156                 {
157                         /* naechsten Namen ermitteln */
158                         chan = strtok( NULL, "," );
159                         continue;
160                 }
161
162                 /* naechsten Namen ermitteln */
163                 chan = strtok( NULL, "," );
164         }
165         return CONNECTED;
166 } /* IRC_PART */
167
168
169 GLOBAL BOOLEAN IRC_TOPIC( CLIENT *Client, REQUEST *Req )
170 {
171         CHANNEL *chan;
172         CLIENT *from;
173         CHAR *topic;
174
175         assert( Client != NULL );
176         assert( Req != NULL );
177
178         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
179
180         /* Falsche Anzahl Parameter? */
181         if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
182
183         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
184         else from = Client;
185         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
186
187         /* Welcher Channel? */
188         chan = Channel_Search( Req->argv[0] );
189         if( ! chan ) return IRC_WriteStrClient( from, ERR_NOTONCHANNEL_MSG, Client_ID( from ), Req->argv[0] );
190
191         /* Ist der User Mitglied in dem Channel? */
192         if( ! Channel_IsMemberOf( chan, from )) return IRC_WriteStrClient( from, ERR_NOTONCHANNEL_MSG, Client_ID( from ), Req->argv[0] );
193
194         if( Req->argc == 1 )
195         {
196                 /* Topic erfragen */
197                 topic = Channel_Topic( chan );
198                 if( *topic ) return IRC_WriteStrClient( from, RPL_TOPIC_MSG, Client_ID( from ), Channel_Name( chan ), topic );
199                 else return IRC_WriteStrClient( from, RPL_NOTOPIC_MSG, Client_ID( from ), Channel_Name( chan ));
200         }
201
202         if( strchr( Channel_Modes( chan ), 't' ))
203         {
204                 /* Topic Lock. Ist der User ein Channel Operator? */
205                 if( ! strchr( Channel_UserModes( chan, from ), 'o' )) return IRC_WriteStrClient( from, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( from ), Channel_Name( chan ));
206         }
207
208         /* Topic setzen */
209         Channel_SetTopic( chan, Req->argv[1] );
210         Log( LOG_DEBUG, "User \"%s\" set topic on \"%s\": %s", Client_Mask( from ), Channel_Name( chan ), Req->argv[1][0] ? Req->argv[1] : "<none>" );
211
212         /* im Channel bekannt machen und an Server weiterleiten */
213         IRC_WriteStrServersPrefix( Client, from, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
214         IRC_WriteStrChannelPrefix( Client, chan, from, FALSE, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
215
216         if( Client_Type( Client ) == CLIENT_USER ) return IRC_WriteStrClientPrefix( Client, Client, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
217         else return CONNECTED;
218 } /* IRC_TOPIC */
219
220
221 GLOBAL BOOLEAN IRC_LIST( CLIENT *Client, REQUEST *Req )
222 {
223         CHAR *pattern;
224         CHANNEL *chan;
225
226         assert( Client != NULL );
227         assert( Req != NULL );
228
229         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
230
231         /* Falsche Anzahl Parameter? */
232         if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
233
234         if( Req->argc > 0 ) pattern = strtok( Req->argv[0], "," );
235         else pattern = "*";
236         
237         while( pattern )
238         {
239                 /* alle Channel durchgehen */
240                 chan = Channel_First( );
241                 while( chan )
242                 {
243                         /* Passt die Suchmaske auf diesen Channel? Bisher werden hier
244                          * "regular expressions" aber noch nicht unterstuetzt ... */
245                         if(( strcasecmp( pattern, Channel_Name( chan )) == 0 ) || ( strcmp( pattern, "*" ) == 0 ))
246                         {
247                                 /* Treffer! */
248                                 if( ! IRC_WriteStrClient( Client, RPL_LIST_MSG, Client_ID( Client), Channel_Name( chan ), Channel_MemberCount( chan ), Channel_Topic( chan ))) return DISCONNECTED;
249                         }
250                         chan = Channel_Next( chan );
251                 }
252                 
253                 /* naechsten Namen ermitteln */
254                 if( Req->argc > 0 ) pattern = strtok( NULL, "," );
255                 else pattern = NULL;
256         }
257         
258         return IRC_WriteStrClient( Client, RPL_LISTEND_MSG, Client_ID( Client ));
259 } /* IRC_LIST */
260
261
262 /* -eof- */