]> jfr.im git - irc/quakenet/lightweight.git/blob - parseline.c
Make L auth to the network when it connects
[irc/quakenet/lightweight.git] / parseline.c
1 /*******************************************************************************
2 *
3 * lightweight - a minimalistic chanserv for ircu's p10-protocol
4 *
5 * copyright 2002 by Rasmus Have & David Mansell
6 *
7 * $Id: parseline.c,v 1.23 2003/09/08 01:19:25 zarjazz Exp $
8 *
9 *******************************************************************************/
10
11 /*
12 This file is part of lightweight.
13
14 lightweight is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
18
19 lightweight is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with lightweight; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 */
28
29 #include <lightweight.h>
30 #include <globalexterns.h>
31 #include <usersdb.h>
32 #include <channelsdb.h>
33 #include <channels.h>
34
35 int ParseLine(void)
36 {
37
38 char *sender;
39 char *command;
40 char *tail;
41
42 /* Make sure we dont have any spaces in front. */
43 sender = StripBlanks(currentline);
44
45 /* Given that every single line is passed through here
46 * I don't see that null lines are a problem. I'm
47 * 99% sure they are simply caused by a chunk ending
48 * between the \r and \n from the server.
49 *
50 * The easiest way to deal with this is simply to bounce
51 * them back here silently. - splidge
52 */
53 if (*sender == '\0')
54 return (0);
55
56 /* fprintf(stderr,"<< %s\n",sender); */
57
58 /* Get the pointer to the next word (the command) and make the sender token zero terminated. */
59 command = SeperateWord(sender);
60
61 /* Get a pointer to the tail and zero terminate the command. */
62 tail = SeperateWord(command);
63
64 /* Switch over the commands we give a fuck about and fuck the rest. */
65
66 if (command[0] == 'B' && command[1] == '\0') {
67 /* Grab the timestamp from the burst */
68 /* a9 B #bar 1016451591 a9AAD:ov,a8AAE:o,a9AAK */
69 char *channel, *timestr, *modestr;
70 struct reggedchannel *chn_ptr;
71 time_t newtimestamp;
72 char buf[512];
73
74 channel = tail;
75 timestr = SeperateWord(channel);
76 modestr = SeperateWord(timestr);
77 SeperateWord(modestr);
78
79 chn_ptr = GetChannelPointer(channel);
80
81 if (chn_ptr != NULL) {
82 newtimestamp = strtol(timestr, NULL, 10);
83
84 SyncTimestamp(chn_ptr, newtimestamp);
85
86 if (IsInviteOnly(chn_ptr) && (!modestr || !strchr(modestr, 'i'))) {
87 /* Channel is bursted without +i but is invite only. Send +i mode. */
88 sprintf(buf, "%sAAA M %s +i\r\n", my_numeric, chn_ptr->channelname);
89 SendLine(buf);
90 }
91 }
92 } else if (command[0] == 'N' && command[1] == '\0') {
93 /* Nick command recieved. */
94 /* Branch on Nick introduction and Nick change. */
95 /* Introdution: Create a new user in the userdb. */
96 /* Change: Update the userdb. */
97
98 if (sender[2] == '\0') {
99 /* Came from server: it's a new user */
100 /* AD N Q 3 000000100 TheQBot CServe.quakenet.org +oiwdk B]AAAB ADAAA :The Q Bot */
101
102 int isoper = 0;
103 char *nick = tail;
104 char *numeric;
105 char *tempstr;
106 char *account = NULL;
107 int i;
108
109 for (i = 0; i < 5; i++)
110 tail = SeperateWord(tail);
111
112 if (*tail == '+') {
113 /* There are usermodes for this user.
114 * We are interested in three things:
115 * - We now need to advance an extra word down the sentence
116 * - Check if the usermodes include +o (oper)
117 * - Check if the usermodes include +r (registered nick)
118 * (and do appropriate things with this information
119 * After this block executes, "tail" will point at the IP address field
120 * (if there were no modes this was true already) */
121
122 tempstr = tail; /* tempstr = list of user modes */
123 tail = SeperateWord(tail);
124 if (IsCharInString('r', tempstr)) {
125 /* Found +r usermode -- that means the user is already authed */
126 /* tail is now pointing at the auth name, so grab that and advance another word */
127 account = tail;
128 tail = SeperateWord(tail);
129 }
130 if (IsCharInString('h', tempstr)) {
131 /* Found +h usermode - just skip the parameter */
132 tail = SeperateWord(tail);
133 }
134 isoper = IsCharInString('o', tempstr);
135 }
136
137 tail = SeperateWord(tail);
138 numeric = tail;
139 SeperateWord(tail);
140
141 UserNickCreation(numeric, nick, isoper);
142
143 if (account != NULL) {
144 /* Account was authed: so call the auth routine now... */
145 AuthUser(numeric, account);
146 }
147 } else {
148 /* Rename */
149 /* [hAAA N splidge_ 1013972401 */
150 char *newnick = tail;
151
152 tail = SeperateWord(tail);
153 UserNickChange(sender, newnick);
154 }
155
156 } else if (command[0] == 'A' && command[1] == 'C' && command[2] == '\0') {
157 /* ACCOUNT command received. */
158 /* Auth the user */
159 /* AD AC [hAAA splidge */
160
161 char *numeric, *account;
162
163 numeric = tail;
164 account = SeperateWord(tail);
165 tail = SeperateWord(tail);
166
167 AuthUser(numeric, account);
168 } else if (command[0] == 'Q' && command[1] == '\0') {
169 /* Quit command recieved. */
170 /* Remove user from userdb. */
171 /* Thank you for flying QuakeNet. */
172 /* [hAAA Q :m00 */
173
174 DeleteUser(sender);
175 } else if (command[0] == 'D' && command[1] == '\0') {
176 /* Kill command received. */
177 /* Much like Quit, this one */
178 /* a9AAD D bcAAQ :frogsquad.netsplit.net!splidge (m00) */
179
180 char *victim = tail;
181
182 tail = SeperateWord(tail);
183
184 DeleteUser(victim);
185 } else if (command[0] == 'J' && command[1] == '\0') {
186 /* Join command recieved. */
187 /* Check if user is authed or if channel is known, whichever is fastest. */
188 /* If authed or if channel is known, check if user has flags on channel, and op/voice the person in that case. */
189
190 /* The only stuff in the tail is the list of channels to join, or 0 */
191 /* Luckily, ircu seems to deal with most of the "JOIN 0" nastiness for us */
192
193 /* a9AAD J #foo,#bar */
194 /* a9AAD J 0 */
195
196 /* Seperate off the second parameter (if any) */
197 SeperateWord(tail);
198
199 DoJoins(sender, tail, 0); /* Last parameter = 0 => this is NOT a CREATE */
200 } else if (command[0] == 'C' && command[1] == '\0') {
201 /* Create command recieved. */
202 /* Check if user is authed or if channel is known, whichever is fastest. */
203 /* If authed or if channel is known, check if user has flags on channel, and op/voice the person in that case. Deop in the opposite case. */
204
205 char *chanlist = tail;
206 char *timestr;
207
208 timestr = SeperateWord(tail);
209 SeperateWord(timestr);
210
211 DoJoins(sender, chanlist, strtol(timestr, NULL, 10)); /* Last parameter = timestamp */
212 } else if (command[0] == 'M' && command[1] == '\0') {
213 /* mode change */
214 /* [hAAA M splidge[wind] :+k */
215 /* [hAAA M #twilightzone -o [hAAA */
216
217 int dir = 1;
218 char *target;
219 char *modes;
220 char *cp;
221 struct user *usrptr;
222
223 target = tail;
224 modes = SeperateWord(target);
225
226 if (target[0] != '#') { /* Not a channel (you don't get mode changes on + channels... */
227 /* This must be a user mode change. Make sure it all checks out */
228 /* Assuming it does, we're only interested in users who are opering or deopering */
229
230 if ((usrptr = FindUserByNumeric(sender)) == NULL) {
231 Error(ERR_PROTOCOL | ERR_WARNING, "Mode change from non-existent user %s", sender);
232 return 0;
233 }
234
235 if (Strcmp(usrptr->nick, target)) {
236 Error(ERR_PROTOCOL | ERR_WARNING, "Mode change for other user (%s) from %s", target, usrptr->nick);
237 return 0;
238 }
239
240 SeperateWord(modes);
241 if (modes == NULL) {
242 Error(ERR_PROTOCOL | ERR_WARNING, "Mode change with no parameters from %s", sender);
243 return 0;
244 }
245
246 for (cp = modes; *cp != '\0'; cp++) { /* Step over each character in the mode string */
247 switch (*cp) {
248
249 case '+':
250 dir = 1;
251 break;
252 case '-':
253 dir = 0;
254 break;
255 case 'o':
256 usrptr->oper = dir;
257 break;
258 }
259 }
260 } else {
261 /* Channel mode change -- which we healthily ignore for now */
262 /* Eeep! Need to examine -i channelmodes, since we introduced invite only channels. */
263 DoChanMode(sender, target, modes);
264 }
265 } else if (command[0] == 'P' && command[1] == '\0') {
266 /* Privmsg command recieved. */
267 /* Usersupport... ugh. */
268 /* a9AAD P #twilightzone :ooops */
269 /* a9AAD P #twilightzone :I missed a field out :) */
270 /* a9AAD P ppAAA :YOU SUCK */
271
272 char *content;
273
274 content = SeperateWord(tail);
275
276 /* Ignore the target (assume it was us..) */
277 /* Note that since we're not doing AUTH we don't need "secure" messages */
278
279 /* Check that the user is authed -- we don't talk to unauthed masses */
280
281 ProcessMessage(sender, content + 1);
282 } else if (command[0] == 'G' && command[1] == '\0') {
283 /* Ping command recieved. */
284 /* Send "Im fine. Weather is good. Send more money.". */
285 char buf[512];
286
287 sprintf(buf, "%s Z %s\r\n", my_numeric, tail);
288 SendLine(buf);
289 } else if (command[0] == 'S' && command[1] == '\0') {
290 /* Server command recieved. */
291 /* Create server in the servertree. */
292 /* AH S hub.uk.quakenet.org 2 0 1013950331 P10 AKAD] 0 :BarrysWorld QuakeNet IRC Server */
293
294 char *servername;
295 int count;
296 int iparentnumeric;
297 int iservernumeric;
298 int imaxusersnumeric;
299
300 servername = tail;
301 for (count = 0; count < 5; count++)
302 tail = SeperateWord(tail);
303
304 iparentnumeric = NumericToLong(sender, 2);
305 iservernumeric = NumericToLong(tail, 2);
306 imaxusersnumeric = NumericToLong(tail + 2, 3) + 1;
307
308 AddServer(iservernumeric, servername, imaxusersnumeric, iparentnumeric);
309 } else if (command[0] == 'S' && command[1] == 'Q' && command[2] == '\0') {
310 /* Server Quit command recieved. */
311 /* Delete server in the servertree and remove all corresponding clients. */
312 /* [h SQ wind.splidge.netsplit.net 0 :Ping timeout */
313
314 char *servername;
315
316 servername = tail;
317 tail = SeperateWord(tail);
318 HandleSquit(servername);
319 } else if (command[0] == 'E' && command[1] == 'B' && command[2] == '\0') {
320 /* End of burst command. */
321 /* If it's OUR server we need to ack */
322 char buf[10];
323
324 /* Quick hack to get some stats whenever a EB is recieved. */
325 UserHashStats();
326
327 if (!strncmp(sender, MyServer, 2)) {
328 /* It was my server which said EB so throw back a EA. */
329 /* We end our own burst here too */
330 burst_done = 1;
331 #ifndef HORRIBLE_DEOPALL_HACK
332 sprintf(buf, "%s EB\r\n", my_numeric);
333 SendLine(buf);
334 sprintf(buf, "%s EA\r\n", my_numeric);
335 SendLine(buf);
336 #endif
337 }
338 } else {
339 /* Crap command recieved. */
340 /* Well, is there anything else we care about? */
341
342 }
343
344 return (1);
345 }