]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/irc.c
- MOTD-Datei ist nun konfigurierbar und wird gelesen.
[ngircd-alex.git] / src / ngircd / irc.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001 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 comBase beteiligten Autoren finden Sie in der Datei AUTHORS.
11  *
12  * $Id: irc.c,v 1.10 2001/12/26 22:48:53 alex Exp $
13  *
14  * irc.c: IRC-Befehle
15  *
16  * $Log: irc.c,v $
17  * Revision 1.10  2001/12/26 22:48:53  alex
18  * - MOTD-Datei ist nun konfigurierbar und wird gelesen.
19  *
20  * Revision 1.9  2001/12/26 14:45:37  alex
21  * - "Code Cleanups".
22  *
23  * Revision 1.8  2001/12/26 03:21:46  alex
24  * - PING/PONG-Befehle implementiert,
25  * - Meldungen ueberarbeitet: enthalten nun (fast) immer den Nick.
26  *
27  * Revision 1.7  2001/12/25 23:25:18  alex
28  * - und nochmal Aenderungen am Logging ;-)
29  *
30  * Revision 1.6  2001/12/25 23:13:33  alex
31  * - Debug-Meldungen angepasst.
32  *
33  * Revision 1.5  2001/12/25 22:02:42  alex
34  * - neuer IRC-Befehl "/QUIT". Verbessertes Logging & Debug-Ausgaben.
35  *
36  * Revision 1.4  2001/12/25 19:19:30  alex
37  * - bessere Fehler-Abfragen, diverse Bugfixes.
38  * - Nicks werden nur einmal vergeben :-)
39  * - /MOTD wird unterstuetzt.
40  *
41  * Revision 1.3  2001/12/24 01:34:06  alex
42  * - USER und NICK wird nun in beliebiger Reihenfolge akzeptiert (wg. BitchX)
43  * - MOTD-Ausgabe begonnen zu implementieren.
44  *
45  * Revision 1.2  2001/12/23 21:57:16  alex
46  * - erste IRC-Befehle zu implementieren begonnen.
47  *
48  * Revision 1.1  2001/12/14 08:13:43  alex
49  * - neues Modul begonnen :-)
50  */
51
52
53 #include <portab.h>
54 #include "global.h"
55
56 #include <imp.h>
57 #include <assert.h>
58 #include <errno.h>
59 #include <stdarg.h>
60 #include <stdio.h>
61 #include <string.h>
62
63 #include "client.h"
64 #include "conf.h"
65 #include "log.h"
66 #include "messages.h"
67 #include "parse.h"
68
69 #include <exp.h>
70 #include "irc.h"
71
72
73 #define CONNECTED TRUE
74 #define DISCONNECTED FALSE
75
76
77 LOCAL BOOLEAN Check_Valid_User( CLIENT *Client );
78
79 LOCAL BOOLEAN Hello_User( CLIENT *Client );
80 LOCAL BOOLEAN Show_MOTD( CLIENT *Client );
81
82
83 GLOBAL VOID IRC_Init( VOID )
84 {
85 } /* IRC_Init */
86
87
88 GLOBAL VOID IRC_Exit( VOID )
89 {
90 } /* IRC_Exit */
91
92
93 GLOBAL BOOLEAN IRC_WriteStrClient( CLIENT *Client, CLIENT *Prefix, CHAR *Format, ... )
94 {
95         /* Text an Clients, lokal bzw. remote, senden. */
96
97         CHAR buffer[1000];
98         BOOLEAN ok = CONNECTED;
99         va_list ap;
100
101         assert( Client != NULL );
102         assert( Format != NULL );
103
104         va_start( ap, Format );
105
106         if( Client->conn_id != NONE )
107         {
108                 /* Lokaler Client */
109                 vsnprintf( buffer, 1000, Format, ap );
110                 if( Prefix ) ok = Conn_WriteStr( Client->conn_id, ":%s %s", Prefix->host, buffer );
111                 else ok = Conn_WriteStr( Client->conn_id, buffer );
112         }
113         else
114         {
115                 /* Remote-Client */
116                 Log( LOG_EMERG, "not implemented: IRC_WriteStrClient()" );
117         }
118
119         va_end( ap );
120         return ok;
121 } /* IRC_WriteStrClient */
122
123
124 GLOBAL BOOLEAN IRC_PASS( CLIENT *Client, REQUEST *Req )
125 {
126         assert( Client != NULL );
127         assert( Req != NULL );
128
129         if( Client->type == CLIENT_UNKNOWN )
130         {
131                 Log( LOG_DEBUG, "Connection %d: got PASS command ...", Client->conn_id );
132                 return IRC_WriteStrClient( Client, This_Server, ERR_UNKNOWNCOMMAND_MSG, Client_Name( Client ), Req->command );
133         }
134         else return IRC_WriteStrClient( Client, This_Server, ERR_ALREADYREGISTRED_MSG, Client_Name( Client ));
135 } /* IRC_PASS */
136
137
138 GLOBAL BOOLEAN IRC_NICK( CLIENT *Client, REQUEST *Req )
139 {
140         assert( Client != NULL );
141         assert( Req != NULL );
142
143         if( Client->type != CLIENT_SERVER && Client->type != CLIENT_SERVICE )
144         {
145                 /* Falsche Anzahl Parameter? */
146                 if( Req->argc != 1 ) return IRC_WriteStrClient( Client, This_Server, ERR_NEEDMOREPARAMS_MSG, Client_Name( Client ), Req->command );
147
148                 /* pruefen, ob Nick bereits vergeben */
149                 if( ! Client_CheckNick( Client, Req->argv[0] )) return CONNECTED;
150
151                 /* Client-Nick registrieren */
152                 strcpy( Client->nick, Req->argv[0] );
153
154                 if( Client->type != CLIENT_USER )
155                 {
156                         /* Neuer Client */
157                         Log( LOG_DEBUG, "Connection %d: got NICK command ...", Client->conn_id );
158                         if( Client->type == CLIENT_GOTUSER ) return Hello_User( Client );
159                         else Client->type = CLIENT_GOTNICK;
160                 }
161                 return CONNECTED;
162         }
163         else return IRC_WriteStrClient( Client, This_Server, ERR_ALREADYREGISTRED_MSG, Client_Name( Client ));
164 } /* IRC_NICK */
165
166
167 GLOBAL BOOLEAN IRC_USER( CLIENT *Client, REQUEST *Req )
168 {
169         assert( Client != NULL );
170         assert( Req != NULL );
171
172         if( Client->type == CLIENT_UNKNOWN || Client->type == CLIENT_GOTNICK || Client->type == CLIENT_GOTPASS )
173         {
174                 /* Falsche Anzahl Parameter? */
175                 if( Req->argc != 4 ) return IRC_WriteStrClient( Client, This_Server, ERR_NEEDMOREPARAMS_MSG, Client_Name( Client ), Req->command );
176
177                 strncpy( Client->user, Req->argv[0], CLIENT_USER_LEN );
178                 Client->user[CLIENT_USER_LEN] = '\0';
179                 strncpy( Client->name, Req->argv[3], CLIENT_NAME_LEN );
180                 Client->name[CLIENT_NAME_LEN] = '\0';
181
182                 Log( LOG_DEBUG, "Connection %d: got USER command ...", Client->conn_id );
183                 if( Client->type == CLIENT_GOTNICK ) return Hello_User( Client );
184                 else Client->type = CLIENT_GOTUSER;
185                 return CONNECTED;
186         }
187         else if( Client->type == CLIENT_USER || Client->type == CLIENT_SERVER || Client->type == CLIENT_SERVICE )
188         {
189                 return IRC_WriteStrClient( Client, This_Server, ERR_ALREADYREGISTRED_MSG, Client_Name( Client ));
190         }
191         else return IRC_WriteStrClient( Client, This_Server, ERR_NOTREGISTERED_MSG, Client_Name( Client ));
192 } /* IRC_USER */
193
194
195 GLOBAL BOOLEAN IRC_QUIT( CLIENT *Client, REQUEST *Req )
196 {
197         assert( Client != NULL );
198         assert( Req != NULL );
199
200         if( Client->type != CLIENT_SERVER && Client->type != CLIENT_SERVICE )
201         {
202                 /* Falsche Anzahl Parameter? */
203                 if( Req->argc > 1 ) return IRC_WriteStrClient( Client, This_Server, ERR_NEEDMOREPARAMS_MSG, Client_Name( Client ), Req->command );
204
205                 Conn_Close( Client->conn_id, "Client wants to quit." );
206                 return DISCONNECTED;
207         }
208         else return IRC_WriteStrClient( Client, This_Server, ERR_NOTREGISTERED_MSG, Client_Name( Client ));
209 } /* IRC_QUIT */
210
211
212 GLOBAL BOOLEAN IRC_PING( CLIENT *Client, REQUEST *Req )
213 {
214         assert( Client != NULL );
215         assert( Req != NULL );
216
217         return IRC_WriteStrClient( Client, This_Server, ERR_UNKNOWNCOMMAND_MSG, Client_Name( Client ), Req->command );
218 } /* IRC_PING */
219
220
221 GLOBAL BOOLEAN IRC_PONG( CLIENT *Client, REQUEST *Req )
222 {
223         assert( Client != NULL );
224         assert( Req != NULL );
225
226         if( ! Check_Valid_User( Client )) return CONNECTED;
227
228         /* Falsche Anzahl Parameter? */
229         if( Req->argc < 1 ) return IRC_WriteStrClient( Client, This_Server, ERR_NOORIGIN_MSG, Client_Name( Client ));
230         if( Req->argc > 1 ) return IRC_WriteStrClient( Client, This_Server, ERR_NEEDMOREPARAMS_MSG, Client_Name( Client ), Req->command );
231
232         /* Der Connection-Timestamp wurde schon beim Lesen aus dem Socket
233          * aktualisiert, daher muss das hier nicht mehr gemacht werden. */
234
235         Log( LOG_DEBUG, "Connection %d: received PONG.", Client->conn_id );
236         return CONNECTED;
237 } /* IRC_PONG */
238
239
240 GLOBAL BOOLEAN IRC_MOTD( CLIENT *Client, REQUEST *Req )
241 {
242         assert( Client != NULL );
243         assert( Req != NULL );
244
245         if( ! Check_Valid_User( Client )) return CONNECTED;
246
247         /* Falsche Anzahl Parameter? */
248         if( Req->argc != 0 ) return IRC_WriteStrClient( Client, This_Server, ERR_NEEDMOREPARAMS_MSG, Client_Name( Client ), Req->command );
249
250         return Show_MOTD( Client );
251 } /* IRC_MOTD */
252
253
254 LOCAL BOOLEAN Check_Valid_User( CLIENT *Client )
255 {
256         assert( Client != NULL );
257
258         if( Client->type != CLIENT_USER )
259         {
260                 IRC_WriteStrClient( Client, This_Server, ERR_NOTREGISTERED_MSG, Client_Name( Client ));
261                 return FALSE;
262         }
263         else return TRUE;
264 } /* Check_Valid_User */
265
266
267 LOCAL BOOLEAN Hello_User( CLIENT *Client )
268 {
269         assert( Client != NULL );
270         assert( Client->nick[0] );
271         
272         Log( LOG_NOTICE, "User \"%s!%s@%s\" (%s) registered.", Client->nick, Client->user, Client->host, Client->name );
273
274         IRC_WriteStrClient( Client, This_Server, RPL_WELCOME_MSG, Client->nick, Client->nick, Client->user, Client->host );
275         IRC_WriteStrClient( Client, This_Server, RPL_YOURHOST_MSG, Client->nick, This_Server->host );
276         IRC_WriteStrClient( Client, This_Server, RPL_CREATED_MSG, Client->nick );
277         IRC_WriteStrClient( Client, This_Server, RPL_MYINFO_MSG, Client->nick, This_Server->host );
278
279         Client->type = CLIENT_USER;
280
281         return Show_MOTD( Client );
282 } /* Hello_User */
283
284
285 LOCAL BOOLEAN Show_MOTD( CLIENT *Client )
286 {
287         BOOLEAN ok;
288         CHAR line[127];
289         FILE *fd;
290         
291         assert( Client != NULL );
292         assert( Client->nick[0] );
293
294         fd = fopen( Conf_MotdFile, "r" );
295         if( ! fd )
296         {
297                 Log( LOG_WARNING, "Can't read MOTD file \"%s\": %s", Conf_MotdFile, strerror( errno ));
298                 return IRC_WriteStrClient( Client, This_Server, ERR_NOMOTD_MSG, Client->nick );
299         }
300         
301         IRC_WriteStrClient( Client, This_Server, RPL_MOTDSTART_MSG, Client->nick, This_Server->host );
302         while( TRUE )
303         {
304                 if( ! fgets( line, 126, fd )) break;
305                 if( line[strlen( line ) - 1] == '\n' ) line[strlen( line ) - 1] = '\0';
306                 IRC_WriteStrClient( Client, This_Server, RPL_MOTD_MSG, Client->nick, line );
307         }
308         ok = IRC_WriteStrClient( Client, This_Server, RPL_ENDOFMOTD_MSG, Client->nick );
309
310         fclose( fd );
311         
312         return ok;
313 } /* Show_MOTD */
314
315
316 /* -eof- */