1 /*
2  * Copyright (c) 2005-2006 William Pitcock, et al.
3  * Rights to this code are documented in doc/LICENSE.
4  *
5  * This file contains protocol support for P10 ircd's.
6  * Some sources used: Run's documentation, beware's description,
7  * raw data sent by asuka.
8  *
9  */
10 
11 #include "atheme.h"
12 #include "uplink.h"
13 #include "pmodule.h"
14 
15 DECLARE_MODULE_V1("protocol/p10-generic", true, _modinit, NULL, PACKAGE_STRING, VENDOR_STRING);
16 
17 static void check_hidehost(user_t *u);
18 
19 /* login to our uplink */
p10_server_login(void)20 static unsigned int p10_server_login(void)
21 {
22 	int ret;
23 
24 	ret = sts("PASS :%s", curr_uplink->send_pass);
25 	if (ret == 1)
26 		return 1;
27 
28 	me.bursting = true;
29 
30 	/* SERVER irc.p10.org 1 933022556 947908144 J10 AA]]] :[127.0.0.1] A Undernet Server */
31 	sts("SERVER %s 1 %lu %lu J10 %s]]] +s6 :%s", me.name, (unsigned long)me.start, (unsigned long)CURRTIME, me.numeric, me.desc);
32 
33 	services_init();
34 
35 	sts("%s EB", me.numeric);
36 
37 	return 0;
38 }
39 
40 /* introduce a client */
p10_introduce_nick(user_t * u)41 static void p10_introduce_nick(user_t *u)
42 {
43 	const char *umode = user_get_umodestr(u);
44 
45 	sts("%s N %s 1 %lu %s %s %sk ]]]]]] %s :%s", me.numeric, u->nick, (unsigned long)u->ts, u->user, u->host, umode, u->uid, u->gecos);
46 }
47 
48 /* invite a user to a channel */
p10_invite_sts(user_t * sender,user_t * target,channel_t * channel)49 static void p10_invite_sts(user_t *sender, user_t *target, channel_t *channel)
50 {
51 	/* target is a nick, weird eh? -- jilles */
52 	sts("%s I %s %s", sender->uid, target->nick, channel->name);
53 }
54 
p10_quit_sts(user_t * u,const char * reason)55 static void p10_quit_sts(user_t *u, const char *reason)
56 {
57 	sts("%s Q :%s", u->uid, reason);
58 }
59 
60 /* WALLOPS wrapper */
p10_wallops_sts(const char * text)61 static void p10_wallops_sts(const char *text)
62 {
63 	sts("%s WA :%s", me.numeric, text);
64 }
65 
66 /* join a channel */
p10_join_sts(channel_t * c,user_t * u,bool isnew,char * modes)67 static void p10_join_sts(channel_t *c, user_t *u, bool isnew, char *modes)
68 {
69 	/* If the channel doesn't exist, we need to create it. */
70 	if (isnew)
71 	{
72 		sts("%s C %s %lu", u->uid, c->name, (unsigned long)c->ts);
73 		if (modes[0] && modes[1])
74 			sts("%s M %s %s", u->uid, c->name, modes);
75 	}
76 	else
77 	{
78 		sts("%s J %s %lu", u->uid, c->name, (unsigned long)c->ts);
79 		sts("%s M %s +o %s", me.numeric, c->name, u->uid);
80 	}
81 }
82 
p10_chan_lowerts(channel_t * c,user_t * u)83 static void p10_chan_lowerts(channel_t *c, user_t *u)
84 {
85 	slog(LG_DEBUG, "p10_chan_lowerts(): lowering TS for %s to %lu",
86 			c->name, (unsigned long)c->ts);
87 	sts("%s B %s %lu %s %s:o", me.numeric, c->name, (unsigned long)c->ts,
88 			channel_modes(c, true), u->uid);
89 	chanban_clear(c);
90 }
91 
92 /* kicks a user from a channel */
p10_kick(user_t * source,channel_t * c,user_t * u,const char * reason)93 static void p10_kick(user_t *source, channel_t *c, user_t *u, const char *reason)
94 {
95 	if (chanuser_find(c, source))
96 		sts("%s K %s %s :%s", source->uid, c->name, u->uid, reason);
97 	else
98 		sts("%s K %s %s :%s", me.numeric, c->name, u->uid, reason);
99 
100 	chanuser_delete(c, u);
101 }
102 
103 /* PRIVMSG wrapper */
p10_msg(const char * from,const char * target,const char * fmt,...)104 static void p10_msg(const char *from, const char *target, const char *fmt, ...)
105 {
106 	va_list ap;
107 	user_t *u = user_find_named(from);
108 	char buf[BUFSIZE];
109 
110 	if (!u)
111 		return;
112 
113 	va_start(ap, fmt);
114 	vsnprintf(buf, BUFSIZE, fmt, ap);
115 	va_end(ap);
116 
117 	sts("%s P %s :%s", u->uid, target, buf);
118 }
119 
p10_msg_global_sts(user_t * from,const char * mask,const char * text)120 static void p10_msg_global_sts(user_t *from, const char *mask, const char *text)
121 {
122 	mowgli_node_t *n;
123 	tld_t *tld;
124 
125 	if (!strcmp(mask, "*"))
126 	{
127 		MOWGLI_ITER_FOREACH(n, tldlist.head)
128 		{
129 			tld = n->data;
130 			sts("%s P %s*%s :%s", from ? from->uid : me.numeric, ircd->tldprefix, tld->name, text);
131 		}
132 	}
133 	else
134 		sts("%s P %s%s :%s", from ? from->uid : me.numeric, ircd->tldprefix, mask, text);
135 }
136 
137 /* NOTICE wrapper */
p10_notice_user_sts(user_t * from,user_t * target,const char * text)138 static void p10_notice_user_sts(user_t *from, user_t *target, const char *text)
139 {
140 	sts("%s O %s :%s", from ? from->uid : me.numeric, target->uid, text);
141 }
142 
p10_notice_global_sts(user_t * from,const char * mask,const char * text)143 static void p10_notice_global_sts(user_t *from, const char *mask, const char *text)
144 {
145 	mowgli_node_t *n;
146 	tld_t *tld;
147 
148 	if (!strcmp(mask, "*"))
149 	{
150 		MOWGLI_ITER_FOREACH(n, tldlist.head)
151 		{
152 			tld = n->data;
153 			sts("%s O %s*%s :%s", from ? from->uid : me.numeric, ircd->tldprefix, tld->name, text);
154 		}
155 	}
156 	else
157 		sts("%s O %s%s :%s", from ? from->uid : me.numeric, ircd->tldprefix, mask, text);
158 }
159 
p10_notice_channel_sts(user_t * from,channel_t * target,const char * text)160 static void p10_notice_channel_sts(user_t *from, channel_t *target, const char *text)
161 {
162 	if (from == NULL || chanuser_find(target, from))
163 		sts("%s O %s :%s", from ? from->uid : me.numeric, target->name, text);
164 	else
165 		sts("%s O %s :[%s:%s] %s", me.numeric, target->name, from->nick, target->name, text);
166 }
167 
p10_wallchops(user_t * sender,channel_t * channel,const char * message)168 static void p10_wallchops(user_t *sender, channel_t *channel, const char *message)
169 {
170 	sts("%s WC %s :%s", sender->uid, channel->name, message);
171 }
172 
173 /* numeric wrapper */
p10_numeric_sts(server_t * from,int numeric,user_t * target,const char * fmt,...)174 static void p10_numeric_sts(server_t *from, int numeric, user_t *target, const char *fmt, ...)
175 {
176 	va_list ap;
177 	char buf[BUFSIZE];
178 
179 	va_start(ap, fmt);
180 	vsnprintf(buf, BUFSIZE, fmt, ap);
181 	va_end(ap);
182 
183 	sts("%s %d %s %s", from->sid, numeric, target->uid, buf);
184 }
185 
186 /* KILL wrapper */
p10_kill_id_sts(user_t * killer,const char * id,const char * reason)187 static void p10_kill_id_sts(user_t *killer, const char *id, const char *reason)
188 {
189 	if (killer != NULL)
190 		sts("%s D %s :%s!%s (%s)", killer->uid, id, killer->host, killer->nick, reason);
191 	else
192 		sts("%s D %s :%s (%s)", me.numeric, id, me.name, reason);
193 }
194 
195 /* PART wrapper */
p10_part_sts(channel_t * c,user_t * u)196 static void p10_part_sts(channel_t *c, user_t *u)
197 {
198 	sts("%s L %s", u->uid, c->name);
199 }
200 
201 /* server-to-server KLINE wrapper */
p10_kline_sts(const char * server,const char * user,const char * host,long duration,const char * reason)202 static void p10_kline_sts(const char *server, const char *user, const char *host, long duration, const char *reason)
203 {
204 	/* hold permanent akills for four weeks -- jilles */
205 	sts("%s GL * +%s@%s %ld :%s", me.numeric, user, host, duration > 0 ? duration : 2419200, reason);
206 }
207 
208 /* server-to-server UNKLINE wrapper */
p10_unkline_sts(const char * server,const char * user,const char * host)209 static void p10_unkline_sts(const char *server, const char *user, const char *host)
210 {
211 	sts("%s GL * -%s@%s", me.numeric, user, host);
212 }
213 
p10_xline_sts(const char * server,const char * realname,long duration,const char * reason)214 static void p10_xline_sts(const char *server, const char *realname, long duration, const char *reason)
215 {
216 	/* hold permanent sglines for four weeks -- jilles */
217 	sts("%s GL * +$R%s %ld :%s", me.numeric, realname, duration > 0 ? duration : 2419200, reason);
218 }
219 
p10_unxline_sts(const char * server,const char * realname)220 static void p10_unxline_sts(const char *server, const char *realname)
221 {
222 	sts("%s GL * -$R%s", me.numeric, realname);
223 }
224 
p10_qline_sts(const char * server,const char * name,long duration,const char * reason)225 static void p10_qline_sts(const char *server, const char *name, long duration, const char *reason)
226 {
227 	if (!VALID_CHANNEL_PFX(name))
228 	{
229 		slog(LG_INFO, "SQLINE: Could not set SQLINE on \2%s\2, not supported by ircu.", name);
230 		return;
231 	}
232 
233 	/* hold permanent sqlines for four weeks -- jilles */
234 	sts("%s GL * +%s %ld :%s", me.numeric, name, duration > 0 ? duration : 2419200, reason);
235 }
236 
p10_unqline_sts(const char * server,const char * name)237 static void p10_unqline_sts(const char *server, const char *name)
238 {
239 	if (!VALID_CHANNEL_PFX(name))
240 	{
241 		slog(LG_INFO, "SQLINE: Could not remove SQLINE on \2%s\2, not supported by ircu.", name);
242 		return;
243 	}
244 
245 	sts("%s GL * -%s", me.numeric, name);
246 }
247 
248 /* topic wrapper */
p10_topic_sts(channel_t * c,user_t * source,const char * setter,time_t ts,time_t prevts,const char * topic)249 static void p10_topic_sts(channel_t *c, user_t *source, const char *setter, time_t ts, time_t prevts, const char *topic)
250 {
251 	if (ts > prevts || prevts == 0)
252 		sts("%s T %s %lu %lu :%s", source->uid, c->name, (unsigned long)c->ts, (unsigned long)ts, topic);
253 	else
254 	{
255 		ts = CURRTIME;
256 		if (ts < prevts)
257 			ts = prevts + 1;
258 		sts("%s T %s %lu %lu :%s", source->uid, c->name, (unsigned long)c->ts, (unsigned long)ts, topic);
259 		c->topicts = ts;
260 	}
261 }
262 
263 /* mode wrapper */
p10_mode_sts(char * sender,channel_t * target,char * modes)264 static void p10_mode_sts(char *sender, channel_t *target, char *modes)
265 {
266 	user_t *fptr;
267 
268 	return_if_fail(sender != NULL);
269 	return_if_fail(target != NULL);
270 	return_if_fail(modes != NULL);
271 
272 	fptr = user_find_named(sender);
273 
274 	return_if_fail(fptr != NULL);
275 
276 	if (chanuser_find(target, fptr))
277 		sts("%s M %s %s", fptr->uid, target->name, modes);
278 	else
279 		sts("%s M %s %s", me.numeric, target->name, modes);
280 }
281 
282 /* ping wrapper */
p10_ping_sts(void)283 static void p10_ping_sts(void)
284 {
285 	sts("%s G !%lu %s %lu", me.numeric, (unsigned long)CURRTIME, me.name, (unsigned long)CURRTIME);
286 }
287 
288 /* protocol-specific stuff to do on login */
p10_on_login(user_t * u,myuser_t * mu,const char * wantedhost)289 static void p10_on_login(user_t *u, myuser_t *mu, const char *wantedhost)
290 {
291 	return_if_fail(u != NULL);
292 
293 	sts("%s AC %s %s %lu", me.numeric, u->uid, entity(mu)->name,
294 			(unsigned long)mu->registered);
295 	check_hidehost(u);
296 }
297 
298 /* P10 does not support logout, so kill the user
299  * we can't keep track of which logins are stale and which aren't -- jilles */
p10_on_logout(user_t * u,const char * account)300 static bool p10_on_logout(user_t *u, const char *account)
301 {
302 	return_val_if_fail(u != NULL, false);
303 
304 	kill_user(NULL, u, "Forcing logout %s -> %s", u->nick, account);
305 	return true;
306 }
307 
p10_jupe(const char * server,const char * reason)308 static void p10_jupe(const char *server, const char *reason)
309 {
310 	server_t *s;
311 
312 	/* hold it for a day (arbitrary) -- jilles */
313 	/* get rid of local deactivation too */
314 	s = server_find(server);
315 	if (s != NULL && s->uplink != NULL)
316 		sts("%s JU %s +%s %d %lu :%s", me.numeric, s->uplink->sid, server, 86400, (unsigned long)CURRTIME, reason);
317 	sts("%s JU * +%s %d %lu :%s", me.numeric, server, 86400, (unsigned long)CURRTIME, reason);
318 }
319 
p10_sasl_sts(char * target,char mode,char * data)320 static void p10_sasl_sts(char *target, char mode, char *data)
321 {
322 	sts("%s XR %c%c %s :SASL:%c:%s", me.numeric, target[0], target[1], target, mode, data);
323 }
324 
p10_svslogin_sts(char * target,char * nick,char * user,char * host,myuser_t * account)325 static void p10_svslogin_sts(char *target, char *nick, char *user, char *host, myuser_t *account)
326 {
327 	sts("%s XR %c%c %s :SASL:L:%s", me.numeric, target[0], target[1], target, entity(account)->name);
328 }
329 
m_topic(sourceinfo_t * si,int parc,char * parv[])330 static void m_topic(sourceinfo_t *si, int parc, char *parv[])
331 {
332 	channel_t *c = channel_find(parv[0]);
333 	const char *source;
334 	time_t ts = 0;
335 
336 	if (!c)
337 		return;
338 
339 	if (si->s != NULL)
340 		source = si->s->name;
341 	else
342 		source = si->su->nick;
343 
344 	if (parc > 2)
345 		ts = atoi(parv[parc - 2]);
346 	if (ts == 0)
347 		ts = CURRTIME;
348 	else if (c->topic != NULL && ts < c->topicts)
349 		return;
350 	handle_topic_from(si, c, source, ts, parv[parc - 1]);
351 }
352 
353 /* AB G !1119920789.573932 services.atheme.org 1119920789.573932 */
m_ping(sourceinfo_t * si,int parc,char * parv[])354 static void m_ping(sourceinfo_t *si, int parc, char *parv[])
355 {
356 	/* reply to PING's */
357 	if (si->su != NULL)
358 		sts("%s Z %s %s", me.numeric, me.numeric, si->su->nick);
359 	else if (parv[0][0] != '!')
360 		sts("%s Z %s %s", me.numeric, me.numeric, si->s->name);
361 	else
362 		sts("%s Z %s %s", me.numeric, me.numeric, parv[0]);
363 }
364 
m_pong(sourceinfo_t * si,int parc,char * parv[])365 static void m_pong(sourceinfo_t *si, int parc, char *parv[])
366 {
367 	me.uplinkpong = CURRTIME;
368 
369 	/* -> :test.projectxero.net PONG test.projectxero.net :shrike.malkier.net */
370 	if (me.bursting)
371 	{
372 #ifdef HAVE_GETTIMEOFDAY
373 		e_time(burstime, &burstime);
374 
375 		slog(LG_INFO, "m_pong(): finished synching with uplink (%d %s)", (tv2ms(&burstime) > 1000) ? (tv2ms(&burstime) / 1000) : tv2ms(&burstime), (tv2ms(&burstime) > 1000) ? "s" : "ms");
376 
377 		wallops("Finished synchronizing with network in %d %s.", (tv2ms(&burstime) > 1000) ? (tv2ms(&burstime) / 1000) : tv2ms(&burstime), (tv2ms(&burstime) > 1000) ? "s" : "ms");
378 #else
379 		slog(LG_INFO, "m_pong(): finished synching with uplink");
380 		wallops("Finished synchronizing with network.");
381 #endif
382 
383 		me.bursting = false;
384 	}
385 }
386 
m_privmsg(sourceinfo_t * si,int parc,char * parv[])387 static void m_privmsg(sourceinfo_t *si, int parc, char *parv[])
388 {
389 	if (parc != 2)
390 		return;
391 
392 	handle_message(si, parv[0], false, parv[1]);
393 }
394 
m_notice(sourceinfo_t * si,int parc,char * parv[])395 static void m_notice(sourceinfo_t *si, int parc, char *parv[])
396 {
397 	if (parc != 2)
398 		return;
399 
400 	handle_message(si, parv[0], true, parv[1]);
401 }
402 
m_create(sourceinfo_t * si,int parc,char * parv[])403 static void m_create(sourceinfo_t *si, int parc, char *parv[])
404 {
405 	char buf[BUFSIZE];
406 	int chanc;
407 	char *chanv[256];
408 	int i;
409 	time_t ts;
410 
411 	chanc = sjtoken(parv[0], ',', chanv);
412 
413 	for (i = 0; i < chanc; i++)
414 	{
415 		channel_t *c = channel_add(chanv[i], ts = atoi(parv[1]), si->su->server);
416 
417 		/* Tell the core to check mode locks now,
418 		 * otherwise it may only happen after the next
419 		 * mode change.
420 		 * P10 does not allow any redundant modes
421 		 * so this will not look ugly. -- jilles */
422 		channel_mode_va(NULL, c, 1, "+");
423 
424 		if (ts <= c->ts)
425 		{
426 			buf[0] = '@';
427 			buf[1] = '\0';
428 		}
429 		else
430 			buf[0] = '\0';
431 
432 		mowgli_strlcat(buf, si->su->uid, BUFSIZE);
433 
434 		chanuser_add(c, buf);
435 	}
436 }
437 
m_join(sourceinfo_t * si,int parc,char * parv[])438 static void m_join(sourceinfo_t *si, int parc, char *parv[])
439 {
440 	int chanc;
441 	char *chanv[256];
442 	int i;
443 	mowgli_node_t *n, *tn;
444 	chanuser_t *cu;
445 
446 	/* JOIN 0 is really a part from all channels */
447 	if (!strcmp(parv[0], "0"))
448 	{
449 		MOWGLI_ITER_FOREACH_SAFE(n, tn, si->su->channels.head)
450 		{
451 			cu = (chanuser_t *) n->data;
452 			chanuser_delete(cu->chan, si->su);
453 		}
454 		return;
455 	}
456 	if (parc < 2)
457 		return;
458 
459 	chanc = sjtoken(parv[0], ',', chanv);
460 
461 	for (i = 0; i < chanc; i++)
462 	{
463 		channel_t *c = channel_find(chanv[i]);
464 
465 		if (!c)
466 		{
467 			c = channel_add(chanv[i], atoi(parv[1]), si->su->server);
468 			channel_mode_va(NULL, c, 1, "+");
469 		}
470 
471 		chanuser_add(c, si->su->uid);
472 	}
473 }
474 
m_burst(sourceinfo_t * si,int parc,char * parv[])475 static void m_burst(sourceinfo_t *si, int parc, char *parv[])
476 {
477 	channel_t *c;
478 	unsigned int modec;
479 	char *modev[16];
480 	unsigned int userc;
481 	char *userv[256];
482 	unsigned int i;
483 	int j;
484 	char prefix[16];
485 	char newnick[16+NICKLEN];
486 	char *p;
487 	time_t ts;
488 	bool keep_new_modes = true;
489 
490 	/* S BURST <channel> <ts> [parameters]
491 	 * parameters can be:
492 	 * +<simple mode>
493 	 * %<bans separated with spaces>
494 	 * <nicks>
495 	 */
496 	ts = atoi(parv[1]);
497 
498 	c = channel_find(parv[0]);
499 
500 	if (c == NULL)
501 	{
502 		slog(LG_DEBUG, "m_burst(): new channel: %s", parv[0]);
503 		c = channel_add(parv[0], ts, si->s);
504 	}
505 	if (ts < c->ts)
506 	{
507 		chanuser_t *cu;
508 		mowgli_node_t *n;
509 
510 		clear_simple_modes(c);
511 		chanban_clear(c);
512 		handle_topic_from(si, c, "", 0, "");
513 		MOWGLI_ITER_FOREACH(n, c->members.head)
514 		{
515 			cu = (chanuser_t *)n->data;
516 			if (cu->user->server == me.me)
517 			{
518 				/* it's a service, reop */
519 				sts("%s M %s +o %s", me.numeric, c->name, CLIENT_NAME(cu->user));
520 				cu->modes = CSTATUS_OP;
521 			}
522 			else
523 				cu->modes = 0;
524 		}
525 
526 		slog(LG_DEBUG, "m_burst(): TS changed for %s (%lu -> %lu)", c->name, (unsigned long)c->ts, (unsigned long)ts);
527 		c->ts = ts;
528 		hook_call_channel_tschange(c);
529 	}
530 	else if (ts > c->ts)
531 		keep_new_modes = false;
532 	if (parc < 3 || parv[2][0] != '+')
533 	{
534 		/* Tell the core to check mode locks now,
535 		 * otherwise it may only happen after the next
536 		 * mode change. -- jilles */
537 		channel_mode_va(NULL, c, 1, "+");
538 	}
539 
540 	j = 2;
541 	while (j < parc)
542 	{
543 		if (parv[j][0] == '+')
544 		{
545 			modec = 0;
546 			modev[modec++] = parv[j++];
547 			if (strchr(modev[0], 'k') && j < parc)
548 				modev[modec++] = parv[j++];
549 			if (strchr(modev[0], 'l') && j < parc)
550 				modev[modec++] = parv[j++];
551 			if (keep_new_modes)
552 				channel_mode(NULL, c, modec, modev);
553 		}
554 		else if (parv[j][0] == '%')
555 		{
556 			userc = sjtoken(parv[j++] + 1, ' ', userv);
557 			if (keep_new_modes)
558 				for (i = 0; i < userc; i++)
559 					chanban_add(c, userv[i], 'b');
560 		}
561 		else
562 		{
563 			userc = sjtoken(parv[j++], ',', userv);
564 
565 			prefix[0] = '\0';
566 			for (i = 0; i < userc; i++)
567 			{
568 				p = strchr(userv[i], ':');
569 				if (p != NULL)
570 				{
571 					*p = '\0';
572 					prefix[0] = '\0';
573 					prefix[1] = '\0';
574 					prefix[2] = '\0';
575 					p++;
576 					if (keep_new_modes)
577 						while (*p)
578 						{
579 							if (*p == 'o' || (*p >= '0' && *p <= '9' && !prefix[0]))
580 								prefix[prefix[0] ? 1 : 0] = '@';
581 							else if (*p == 'v')
582 								prefix[prefix[0] ? 1 : 0] = '+';
583 							p++;
584 						}
585 				}
586 				mowgli_strlcpy(newnick, prefix, sizeof newnick);
587 				mowgli_strlcat(newnick, userv[i], sizeof newnick);
588 				chanuser_add(c, newnick);
589 			}
590 		}
591 	}
592 
593 	if (c->nummembers == 0 && !(c->modes & ircd->perm_mode))
594 		channel_delete(c);
595 }
596 
m_part(sourceinfo_t * si,int parc,char * parv[])597 static void m_part(sourceinfo_t *si, int parc, char *parv[])
598 {
599 	int chanc;
600 	char *chanv[256];
601 	int i;
602 
603 	chanc = sjtoken(parv[0], ',', chanv);
604 	for (i = 0; i < chanc; i++)
605 	{
606 		slog(LG_DEBUG, "m_part(): user left channel: %s -> %s", si->su->nick, chanv[i]);
607 
608 		chanuser_delete(channel_find(chanv[i]), si->su);
609 	}
610 }
611 
m_nick(sourceinfo_t * si,int parc,char * parv[])612 static void m_nick(sourceinfo_t *si, int parc, char *parv[])
613 {
614 	user_t *u;
615 	char ipstring[HOSTIPLEN];
616 	char *p;
617 
618 	/* got the right number of args for an introduction? */
619 	if (parc >= 8)
620 	{
621 		/* -> AB N jilles 1 1137687480 jilles jaguar.test +oiwgrx jilles B]AAAB ABAAE :Jilles Tjoelker */
622 		/* -> AB N test4 1 1137690148 jilles jaguar.test +iw B]AAAB ABAAG :Jilles Tjoelker */
623 		slog(LG_DEBUG, "m_nick(): new user on `%s': %s", si->s->name, parv[0]);
624 
625 		decode_p10_ip(parv[parc - 3], ipstring);
626 		u = user_add(parv[0], parv[3], parv[4], NULL, ipstring, parv[parc - 2], parv[parc - 1], si->s, atoi(parv[2]));
627 		if (u == NULL)
628 			return;
629 
630 		if (parv[5][0] == '+')
631 		{
632 			user_mode(u, parv[5]);
633 			if (strchr(parv[5], 'r'))
634 			{
635 				p = strchr(parv[6], ':');
636 				if (p != NULL)
637 					*p++ = '\0';
638 				handle_burstlogin(u, parv[6], p ? atol(p) : 0);
639 				/* killed to force logout? */
640 				if (user_find(parv[parc - 2]) == NULL)
641 					return;
642 			}
643 			if (strchr(parv[5], 'x'))
644 			{
645 				u->flags |= UF_HIDEHOSTREQ;
646 				/* this must be after setting the account name */
647 				check_hidehost(u);
648 			}
649 		}
650 
651 		handle_nickchange(u);
652 	}
653 	/* if it's only 2 then it's a nickname change */
654 	else if (parc == 2)
655 	{
656 		if (!si->su)
657 		{
658 			slog(LG_DEBUG, "m_nick(): server trying to change nick: %s", si->s != NULL ? si->s->name : "<none>");
659 			return;
660 		}
661 
662 		slog(LG_DEBUG, "m_nick(): nickname change from `%s': %s", si->su->nick, parv[0]);
663 
664 		if (user_changenick(si->su, parv[0], atoi(parv[1])))
665 			return;
666 
667 		handle_nickchange(si->su);
668 	}
669 	else
670 	{
671 		int i;
672 		slog(LG_DEBUG, "m_nick(): got NICK with wrong (%d) number of params", parc);
673 
674 		for (i = 0; i < parc; i++)
675 			slog(LG_DEBUG, "m_nick():   parv[%d] = %s", i, parv[i]);
676 	}
677 }
678 
m_quit(sourceinfo_t * si,int parc,char * parv[])679 static void m_quit(sourceinfo_t *si, int parc, char *parv[])
680 {
681 	slog(LG_DEBUG, "m_quit(): user leaving: %s", si->su->nick);
682 
683 	/* user_delete() takes care of removing channels and so forth */
684 	user_delete(si->su, parv[0]);
685 }
686 
m_mode(sourceinfo_t * si,int parc,char * parv[])687 static void m_mode(sourceinfo_t *si, int parc, char *parv[])
688 {
689 	user_t *u;
690 	channel_t *c;
691 	int i;
692 	char *p;
693 	int dir = MTYPE_ADD;
694 	time_t ts;
695 
696 	if (*parv[0] == '#')
697 	{
698 		c = channel_find(parv[0]);
699 		if (c == NULL)
700 			return;
701 		i = 2;
702 		for (p = parv[1]; *p != '\0'; p++)
703 		{
704 			switch (*p)
705 			{
706 				case '+': dir = MTYPE_ADD; break;
707 				case '-': dir = MTYPE_DEL; break;
708 				case 'l':
709 					  if (dir == MTYPE_DEL)
710 						  break;
711 					  /* FALLTHROUGH */
712 				case 'b': case 'k': case 'o': case 'v':
713 					  i++;
714 			}
715 		}
716 		if (i < parc && (ts = atoi(parv[i])) != 0)
717 		{
718 			if (ts > c->ts)
719 			{
720 				slog(LG_DEBUG, "m_mode(): ignoring mode on %s (%lu > %lu)", c->name, (unsigned long)ts, (unsigned long)c->ts);
721 				return;
722 			}
723 		}
724 		channel_mode(NULL, c, parc - 1, &parv[1]);
725 	}
726 	else
727 	{
728 		/* Yes this is a nick and not a UID -- jilles */
729 		u = user_find_named(parv[0]);
730 		if (u == NULL)
731 		{
732 			slog(LG_DEBUG, "m_mode(): user mode for unknown user %s", parv[0]);
733 			return;
734 		}
735 		user_mode(u, parv[1]);
736 		if (strchr(parv[1], 'x'))
737 		{
738 			u->flags |= UF_HIDEHOSTREQ;
739 			check_hidehost(u);
740 		}
741 	}
742 }
743 
m_clearmode(sourceinfo_t * si,int parc,char * parv[])744 static void m_clearmode(sourceinfo_t *si, int parc, char *parv[])
745 {
746 	channel_t *chan;
747 	char *p, c;
748 	mowgli_node_t *n;
749 	chanuser_t *cu;
750 	int i;
751 
752 	/* -> ABAAA CM # b */
753 	/* Note: this is an IRCop command, do not enforce mode locks. */
754 	chan = channel_find(parv[0]);
755 	if (chan == NULL)
756 	{
757 		slog(LG_DEBUG, "m_clearmode(): unknown channel %s", parv[0]);
758 		return;
759 	}
760 	p = parv[1];
761 	while ((c = *p++))
762 	{
763 		if (c == 'b')
764 			chanban_clear(chan);
765 		else if (c == 'k')
766 		{
767 			if (chan->key)
768 				free(chan->key);
769 			chan->key = NULL;
770 		}
771 		else if (c == 'l')
772 			chan->limit = 0;
773 		else if (c == 'o')
774 		{
775 			MOWGLI_ITER_FOREACH(n, chan->members.head)
776 			{
777 				cu = (chanuser_t *)n->data;
778 				if (cu->user->server == me.me)
779 				{
780 					/* it's a service, reop */
781 					sts("%s M %s +o %s", me.numeric,
782 							chan->name,
783 							cu->user->uid);
784 				}
785 				else
786 					cu->modes &= ~CSTATUS_OP;
787 			}
788 		}
789 		else if (c == 'v')
790 		{
791 			MOWGLI_ITER_FOREACH(n, chan->members.head)
792 			{
793 				cu = (chanuser_t *)n->data;
794 				cu->modes &= ~CSTATUS_VOICE;
795 			}
796 		}
797 		else
798 			for (i = 0; mode_list[i].mode != '\0'; i++)
799 			{
800 				if (c == mode_list[i].mode)
801 					chan->modes &= ~mode_list[i].value;
802 			}
803 	}
804 }
805 
m_kick(sourceinfo_t * si,int parc,char * parv[])806 static void m_kick(sourceinfo_t *si, int parc, char *parv[])
807 {
808 	user_t *u = user_find(parv[1]);
809 	channel_t *c = channel_find(parv[0]);
810 
811 	/* -> :rakaur KICK #shrike rintaun :test */
812 	slog(LG_DEBUG, "m_kick(): user was kicked: %s -> %s", parv[1], parv[0]);
813 
814 	if (!u)
815 	{
816 		slog(LG_DEBUG, "m_kick(): got kick for nonexistant user %s", parv[1]);
817 		return;
818 	}
819 
820 	if (!c)
821 	{
822 		slog(LG_DEBUG, "m_kick(): got kick in nonexistant channel: %s", parv[0]);
823 		return;
824 	}
825 
826 	if (!chanuser_find(c, u))
827 	{
828 		slog(LG_DEBUG, "m_kick(): got kick for %s not in %s", u->nick, c->name);
829 		return;
830 	}
831 
832 	chanuser_delete(c, u);
833 
834 	/* if they kicked us, let's rejoin */
835 	if (is_internal_client(u))
836 	{
837 		slog(LG_DEBUG, "m_kick(): %s got kicked from %s; rejoining", u->nick, parv[0]);
838 		join(parv[0], u->nick);
839 	}
840 }
841 
m_kill(sourceinfo_t * si,int parc,char * parv[])842 static void m_kill(sourceinfo_t *si, int parc, char *parv[])
843 {
844 	handle_kill(si, parv[0], parc > 1 ? parv[1] : "<No reason given>");
845 }
846 
m_squit(sourceinfo_t * si,int parc,char * parv[])847 static void m_squit(sourceinfo_t *si, int parc, char *parv[])
848 {
849 	slog(LG_DEBUG, "m_squit(): server leaving: %s from %s", parv[0], parv[1]);
850 	server_delete(parv[0]);
851 }
852 
853 /* SERVER ircu.devel.atheme.org 1 1119902586 1119908830 J10 ABAP] + :lets lol */
m_server(sourceinfo_t * si,int parc,char * parv[])854 static void m_server(sourceinfo_t *si, int parc, char *parv[])
855 {
856 	server_t *s;
857 
858 	/* We dont care about the max connections. */
859 	parv[5][2] = '\0';
860 
861 	slog(LG_DEBUG, "m_server(): new server: %s, id %s, %s",
862 			parv[0], parv[5],
863 			parv[4][0] == 'P' ? "eob" : "bursting");
864 	s = handle_server(si, parv[0], parv[5], atoi(parv[1]), parv[7]);
865 
866 	/* SF_EOB may only be set when we have all users on the server.
867 	 * so store the fact that they are EOB in another flag.
868 	 * handle_eob() will set SF_EOB when the uplink has finished bursting.
869 	 * -- jilles */
870 	if (s != NULL && parv[4][0] == 'P')
871 		s->flags |= SF_EOB2;
872 }
873 
m_stats(sourceinfo_t * si,int parc,char * parv[])874 static void m_stats(sourceinfo_t *si, int parc, char *parv[])
875 {
876 	handle_stats(si->su, parv[0][0]);
877 }
878 
m_admin(sourceinfo_t * si,int parc,char * parv[])879 static void m_admin(sourceinfo_t *si, int parc, char *parv[])
880 {
881 	handle_admin(si->su);
882 }
883 
m_version(sourceinfo_t * si,int parc,char * parv[])884 static void m_version(sourceinfo_t *si, int parc, char *parv[])
885 {
886 	handle_version(si->su);
887 }
888 
m_info(sourceinfo_t * si,int parc,char * parv[])889 static void m_info(sourceinfo_t *si, int parc, char *parv[])
890 {
891 	handle_info(si->su);
892 }
893 
m_motd(sourceinfo_t * si,int parc,char * parv[])894 static void m_motd(sourceinfo_t *si, int parc, char *parv[])
895 {
896 	handle_motd(si->su);
897 }
898 
m_whois(sourceinfo_t * si,int parc,char * parv[])899 static void m_whois(sourceinfo_t *si, int parc, char *parv[])
900 {
901 	handle_whois(si->su, parv[1]);
902 }
903 
m_trace(sourceinfo_t * si,int parc,char * parv[])904 static void m_trace(sourceinfo_t *si, int parc, char *parv[])
905 {
906 	handle_trace(si->su, parv[0], parc >= 2 ? parv[1] : NULL);
907 }
908 
m_away(sourceinfo_t * si,int parc,char * parv[])909 static void m_away(sourceinfo_t *si, int parc, char *parv[])
910 {
911 	handle_away(si->su, parc >= 1 ? parv[0] : NULL);
912 }
913 
m_pass(sourceinfo_t * si,int parc,char * parv[])914 static void m_pass(sourceinfo_t *si, int parc, char *parv[])
915 {
916 	if (strcmp(curr_uplink->receive_pass, parv[0]))
917 	{
918 		slog(LG_INFO, "m_pass(): password mismatch from uplink; aborting");
919 		runflags |= RF_SHUTDOWN;
920 	}
921 }
922 
m_error(sourceinfo_t * si,int parc,char * parv[])923 static void m_error(sourceinfo_t *si, int parc, char *parv[])
924 {
925 	slog(LG_INFO, "m_error(): error from server: %s", parv[0]);
926 }
927 
m_eos(sourceinfo_t * si,int parc,char * parv[])928 static void m_eos(sourceinfo_t *si, int parc, char *parv[])
929 {
930 	handle_eob(si->s);
931 
932 	/* acknowledge a local END_OF_BURST */
933 	if (si->s->uplink == me.me)
934 		sts("%s EA", me.numeric);
935 }
936 
m_account(sourceinfo_t * si,int parc,char * parv[])937 static void m_account(sourceinfo_t *si, int parc, char *parv[])
938 {
939 	user_t *u;
940 
941 	u = user_find(parv[0]);
942 	if (u == NULL)
943 		return;
944 	handle_setlogin(si, u, parv[1], parc > 2 ? atol(parv[2]) : 0);
945 }
946 
check_hidehost(user_t * u)947 static void check_hidehost(user_t *u)
948 {
949 	static bool warned = false;
950 	char buf[HOSTLEN + 1];
951 
952 	/* do they qualify? */
953 	if (!(u->flags & UF_HIDEHOSTREQ) || u->myuser == NULL || (u->myuser->flags & MU_WAITAUTH))
954 		return;
955 	/* don't use this if they have some other kind of vhost */
956 	if (strcmp(u->host, u->vhost))
957 	{
958 		slog(LG_DEBUG, "check_hidehost(): +x overruled by other vhost for %s", u->nick);
959 		return;
960 	}
961 	if (me.hidehostsuffix == NULL)
962 	{
963 		if (!warned)
964 		{
965 			wallops("Misconfiguration: serverinfo::hidehostsuffix not set");
966 			warned = true;
967 		}
968 		return;
969 	}
970 
971 	snprintf(buf, sizeof buf, "%s.%s", entity(u->myuser)->name, me.hidehostsuffix);
972 
973 	strshare_unref(u->vhost);
974 	u->vhost = strshare_get(buf);
975 
976 	slog(LG_DEBUG, "check_hidehost(): %s -> %s", u->nick, u->vhost);
977 }
978 
_modinit(module_t * m)979 void _modinit(module_t * m)
980 {
981 	MODULE_TRY_REQUEST_DEPENDENCY(m, "transport/p10");
982 	MODULE_TRY_REQUEST_DEPENDENCY(m, "protocol/base36uid");
983 
984 	/* Symbol relocation voodoo. */
985 	server_login = &p10_server_login;
986 	introduce_nick = &p10_introduce_nick;
987 	quit_sts = &p10_quit_sts;
988 	wallops_sts = &p10_wallops_sts;
989 	join_sts = &p10_join_sts;
990 	chan_lowerts = &p10_chan_lowerts;
991 	kick = &p10_kick;
992 	msg = &p10_msg;
993 	msg_global_sts = &p10_msg_global_sts;
994 	notice_user_sts = &p10_notice_user_sts;
995 	notice_global_sts = &p10_notice_global_sts;
996 	notice_channel_sts = &p10_notice_channel_sts;
997 	wallchops = &p10_wallchops;
998 	numeric_sts = &p10_numeric_sts;
999 	kill_id_sts = &p10_kill_id_sts;
1000 	part_sts = &p10_part_sts;
1001 	kline_sts = &p10_kline_sts;
1002 	unkline_sts = &p10_unkline_sts;
1003 	xline_sts = &p10_xline_sts;
1004 	unxline_sts = &p10_unxline_sts;
1005 	qline_sts = &p10_qline_sts;
1006 	unqline_sts = &p10_unqline_sts;
1007 	topic_sts = &p10_topic_sts;
1008 	mode_sts = &p10_mode_sts;
1009 	ping_sts = &p10_ping_sts;
1010 	ircd_on_login = &p10_on_login;
1011 	ircd_on_logout = &p10_on_logout;
1012 	jupe = &p10_jupe;
1013 	invite_sts = &p10_invite_sts;
1014 	sasl_sts = &p10_sasl_sts;
1015 	svslogin_sts = &p10_svslogin_sts;
1016 
1017 	pcommand_add("G", m_ping, 1, MSRC_USER | MSRC_SERVER);
1018 	pcommand_add("Z", m_pong, 1, MSRC_SERVER);
1019 	pcommand_add("P", m_privmsg, 2, MSRC_USER);
1020 	pcommand_add("O", m_notice, 2, MSRC_USER | MSRC_SERVER);
1021 	pcommand_add("NOTICE", m_notice, 2, MSRC_UNREG);
1022 	pcommand_add("C", m_create, 1, MSRC_USER);
1023 	pcommand_add("J", m_join, 1, MSRC_USER);
1024 	pcommand_add("EB", m_eos, 0, MSRC_SERVER);
1025 	pcommand_add("B", m_burst, 2, MSRC_SERVER);
1026 	pcommand_add("L", m_part, 1, MSRC_USER);
1027 	pcommand_add("N", m_nick, 2, MSRC_USER | MSRC_SERVER);
1028 	pcommand_add("Q", m_quit, 1, MSRC_USER);
1029 	pcommand_add("M", m_mode, 2, MSRC_USER | MSRC_SERVER);
1030 	pcommand_add("OM", m_mode, 2, MSRC_USER); /* OPMODE, treat as MODE */
1031 	pcommand_add("CM", m_clearmode, 2, MSRC_USER);
1032 	pcommand_add("K", m_kick, 2, MSRC_USER | MSRC_SERVER);
1033 	pcommand_add("OK", m_kick, 2, MSRC_USER); /* OPKICK, treat as KICK */
1034 	pcommand_add("D", m_kill, 1, MSRC_USER | MSRC_SERVER);
1035 	pcommand_add("SQ", m_squit, 1, MSRC_USER | MSRC_SERVER);
1036 	pcommand_add("S", m_server, 8, MSRC_SERVER);
1037 	pcommand_add("SERVER", m_server, 8, MSRC_UNREG);
1038 	pcommand_add("R", m_stats, 2, MSRC_USER);
1039 	pcommand_add("AD", m_admin, 1, MSRC_USER);
1040 	pcommand_add("V", m_version, 1, MSRC_USER);
1041 	pcommand_add("F", m_info, 1, MSRC_USER);
1042 	pcommand_add("W", m_whois, 2, MSRC_USER);
1043 	pcommand_add("TR", m_trace, 1, MSRC_USER);
1044 	pcommand_add("A", m_away, 0, MSRC_USER);
1045 	pcommand_add("PASS", m_pass, 1, MSRC_UNREG);
1046 	pcommand_add("Y", m_error, 1, MSRC_UNREG | MSRC_SERVER);
1047 	pcommand_add("ERROR", m_error, 1, MSRC_UNREG | MSRC_SERVER);
1048 	pcommand_add("T", m_topic, 2, MSRC_USER | MSRC_SERVER);
1049 	pcommand_add("MO", m_motd, 1, MSRC_USER);
1050 	pcommand_add("AC", m_account, 2, MSRC_SERVER);
1051 
1052 	m->mflags = MODTYPE_CORE;
1053 }
1054 
1055 /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
1056  * vim:ts=8
1057  * vim:sw=8
1058  * vim:noexpandtab
1059  */
1060