1 /************************************************************************
2  *   IRC - Internet Relay Chat, ircd/s_service.c
3  *   Copyright (C) 1990 Jarkko Oikarinen and
4  *                      University of Oulu, Computing Center
5  *
6  *   See file AUTHORS in IRC package for additional names of
7  *   the programmers.
8  *
9  *   This program is free software; you can redistribute it and/or modify
10  *   it under the terms of the GNU General Public License as published by
11  *   the Free Software Foundation; either version 1, or (at your option)
12  *   any later version.
13  *
14  *   This program is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *   GNU General Public License for more details.
18  *
19  *   You should have received a copy of the GNU General Public License
20  *   along with this program; if not, write to the Free Software
21  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23 
24 #ifndef lint
25 static const volatile char rcsid[] = "@(#)$Id: s_service.c,v 1.69 2010/08/12 01:08:02 bif Exp $";
26 #endif
27 
28 #include "os.h"
29 #include "s_defines.h"
30 #define S_SERVICE_C
31 #include "s_externs.h"
32 #undef S_SERVICE_C
33 
34 aService	*svctop = NULL;
35 
make_service(aClient * cptr)36 aService	*make_service(aClient *cptr)
37 {
38 	Reg	aService	*svc = cptr->service;
39 
40 	if (svc)
41 		return svc;
42 
43 	cptr->service = svc = (aService *)MyMalloc(sizeof(*svc));
44 	bzero((char *)svc, sizeof(*svc));
45 	cptr->name = svc->namebuf;
46 	svc->bcptr = cptr;
47 	if (svctop)
48 		svctop->prevs = svc;
49 	svc->nexts = svctop;
50 	svc->prevs = NULL; /* useless */
51 	svctop = svc;
52 	return svc;
53 }
54 
55 
free_service(aClient * cptr)56 void	free_service(aClient *cptr)
57 {
58 	aService	*serv;
59 
60 	if ((serv = cptr->service))
61 	{
62 		if (serv->nexts)
63 			serv->nexts->prevs = serv->prevs;
64 		if (serv->prevs)
65 			serv->prevs->nexts = serv->nexts;
66 		if (svctop == serv)
67 			svctop = serv->nexts;
68 		/* It's just the pointer, not even allocated in m_service.
69 		 * Why would someone want to destroy that struct here?
70 		 * So far commenting it out. --B.
71 		if (serv->servp)
72 			free_server(serv->servp, cptr);
73 		 */
74 		/* this is ok, ->server is a string. */
75 		if (serv->server)
76 			MyFree(serv->server);
77 		MyFree(serv);
78 		cptr->service = NULL;
79 	}
80 }
81 
82 
best_service(char * name,aClient * cptr)83 static	aClient *best_service(char *name, aClient *cptr)
84 {
85 	Reg	aClient	*acptr = NULL;
86 	Reg	aClient	*bcptr;
87 	Reg	aService *sp;
88 	int	len = strlen(name);
89 
90 	if (!index(name, '@') || !(acptr = find_service(name, cptr)))
91 		for (sp = svctop; sp; sp = sp->nexts)
92 			if ((bcptr = sp->bcptr) &&
93 			    !myncmp(name, bcptr->name, len))
94 			    {
95 				if (!acptr || bcptr->hopcount < acptr->hopcount)
96 				{
97 					acptr = bcptr;
98 				}
99 			    }
100 	return (acptr ? acptr : cptr);
101 }
102 
103 
104 #ifdef	USE_SERVICES
105 /*
106 ** check_services_butone
107 **	check all local services except `cptr', and send `fmt' according to:
108 **	action	type on notice
109 **	server	origin
110 */
check_services_butone(long action,aServer * servp,aClient * cptr,char * fmt,...)111 void	check_services_butone(long action, aServer *servp, aClient *cptr,
112 		char *fmt, ...)
113 /* shouldn't cptr be named sptr? */
114 {
115 	char	nbuf[NICKLEN + USERLEN + HOSTLEN + 3];
116 	Reg	aService *sp;
117 
118 	*nbuf = '\0';
119 	for (sp = svctop; sp; sp = sp->nexts)
120 	{
121 		if (!MyConnect(sp->bcptr) ||
122 		    (cptr && sp->bcptr == cptr->from))
123 		{
124 			continue;
125 		}
126 		/*
127 		** found a (local) service, check if action matches what's
128 		** wanted AND if it comes from a server matching the dist
129 		*/
130 		if ((sp->wants & action)
131 		    && (!servp || !match(sp->dist, servp->bcptr->name)
132 			|| !match(sp->dist, servp->sid)))
133 		{
134 			if ((sp->wants & (SERVICE_WANT_PREFIX|SERVICE_WANT_UID))
135 			    && cptr && IsRegisteredUser(cptr) &&
136 			    (action & SERVICE_MASK_PREFIX))
137 			{
138 				char	buf[2048];
139 				va_list	va;
140 				va_start(va, fmt);
141 				(void)va_arg(va, char *);
142 				vsprintf(buf, fmt+3, va);
143 				va_end(va);
144 				if ((sp->wants & SERVICE_WANT_UID))
145 					sendto_one(sp->bcptr, ":%s%s",
146 						cptr->user ? cptr->user->uid :
147 						cptr->name, buf);
148 				else
149 					sendto_one(sp->bcptr, ":%s!%s@%s%s",
150 						cptr->name, cptr->user->username,
151 						cptr->user->host, buf);
152 			}
153 			else
154 			{
155 				va_list	va;
156 				va_start(va, fmt);
157 				vsendto_one(sp->bcptr, fmt, va);
158 				va_end(va);
159 			}
160 		}
161 	}
162 	return;
163 }
164 
165 /*
166 ** sendnum_toone
167 **	send the NICK + USER + UMODE for sptr to cptr according to wants
168 */
sendnum_toone(aClient * cptr,int wants,aClient * sptr,char * umode)169 static	void	sendnum_toone(aClient *cptr, int wants, aClient *sptr,
170 			char *umode)
171 {
172 
173 	if (!*umode)
174 		umode = "+";
175 
176 	if ((wants & SERVICE_WANT_UID) && sptr->user)
177 		sendto_one(cptr, ":%s UNICK %s %s %s %s %s %s :%s",
178 			sptr->user->servp->sid,
179 			(wants & SERVICE_WANT_NICK) ? sptr->name : ".",
180 			sptr->user->uid,
181 			(wants & SERVICE_WANT_USER) ? sptr->user->username : ".",
182 			(wants & SERVICE_WANT_USER) ? sptr->user->host : ".",
183 			(wants & SERVICE_WANT_USER) ? sptr->user->sip : ".",
184 			(wants & (SERVICE_WANT_UMODE|SERVICE_WANT_OPER)) ? umode : "+",
185 			(wants & SERVICE_WANT_USER) ? sptr->info : "");
186 	else
187 	if (wants & SERVICE_WANT_EXTNICK)
188 		/* extended NICK syntax */
189 		sendto_one(cptr, "NICK %s %d %s %s %s %s :%s",
190 			   (wants & SERVICE_WANT_NICK) ? sptr->name : ".",
191 			   sptr->hopcount + 1,
192 			   (wants & SERVICE_WANT_USER) ? sptr->user->username
193 			   : ".",
194 			   (wants & SERVICE_WANT_USER) ? sptr->user->host :".",
195 			   (wants & SERVICE_WANT_USER) ?
196 			   ((wants & SERVICE_WANT_SID) ?
197 			    sptr->user->servp->sid : sptr->user->server) : ".",
198 			   (wants & (SERVICE_WANT_UMODE|SERVICE_WANT_OPER)) ? umode : "+",
199 			   (wants & SERVICE_WANT_USER) ? sptr->info : "");
200 	else
201 		/* old style NICK + USER + UMODE */
202 	    {
203 		char    nbuf[NICKLEN + USERLEN + HOSTLEN + 3];
204 		char    *prefix;
205 
206 		if (wants & SERVICE_WANT_PREFIX)
207 		    {
208 			sprintf(nbuf, "%s!%s@%s", sptr->name,
209 				sptr->user->username, sptr->user->host);
210 			prefix = nbuf;
211 		    }
212 		else
213 			prefix = sptr->name;
214 
215 		if (wants & SERVICE_WANT_NICK)
216 			sendto_one(cptr, "NICK %s :%d", sptr->name,
217 				   sptr->hopcount+1);
218 		if (wants & SERVICE_WANT_USER)
219 			sendto_one(cptr, ":%s USER %s %s %s :%s", prefix,
220 				   sptr->user->username, sptr->user->host,
221 				   (wants & SERVICE_WANT_SID)?
222 				   sptr->user->servp->sid : sptr->user->server,
223 				   sptr->info);
224 		if (wants & (SERVICE_WANT_UMODE|SERVICE_WANT_OPER))
225 			sendto_one(cptr, ":%s MODE %s %s", prefix, sptr->name,
226 				   umode);
227 	    }
228 }
229 
230 /*
231 ** check_services_num
232 **	check all local services to eventually send NICK + USER + UMODE
233 **	for new client sptr
234 */
check_services_num(aClient * sptr,char * umode)235 void	check_services_num(aClient *sptr, char *umode)
236 {
237 	Reg	aService *sp;
238 
239 	for (sp = svctop; sp; sp = sp->nexts)
240 	{
241 		if (!MyConnect(sp->bcptr))
242 		{
243 			continue;
244 		}
245 		/*
246 		** found a (local) service, check if action matches what's
247 		** wanted AND if it comes from a server matching the dist
248 		*/
249 		if ((sp->wants & SERVICE_MASK_NUM)
250 		    && (!match(sp->dist, sptr->user->server)
251 				|| !match(sp->dist, sptr->user->servp->sid)))
252 		{
253 			sendnum_toone(sp->bcptr, sp->wants, sptr,
254 				      umode);
255 		}
256 	}
257 }
258 
259 
find_conf_service(aClient * cptr,int type,aConfItem * aconf)260 aConfItem	*find_conf_service(aClient *cptr, int type, aConfItem *aconf)
261 {
262 	static	char	uhost[HOSTLEN+USERLEN+3];
263 	Reg	aConfItem *tmp;
264 	char	*s;
265 	struct	hostent	*hp;
266 	int	i;
267 
268 	for (tmp = conf; tmp; tmp = tmp->next)
269 	    {
270 		/*
271 		** Accept if the *real* hostname (usually sockethost)
272 		** matches host field of the configuration, the name field
273 		** is the same, the type match is correct and nobody else
274 		** is using this S-line.
275 		*/
276 		if (!(tmp->status & CONF_SERVICE))
277 			continue;
278 		Debug((DEBUG_INFO,"service: cl=%d host (%s) name (%s) port=%d",
279 			tmp->clients, tmp->host, tmp->name, tmp->port));
280 		Debug((DEBUG_INFO,"service: host (%s) name (%s) type=%d",
281 			cptr->sockhost, cptr->name, type));
282 		if (tmp->clients || (type && tmp->port != type) ||
283 		    mycmp(tmp->name, cptr->name))
284 			continue;
285 	 	if ((hp = cptr->hostp))
286 			for (s = hp->h_name, i = 0; s; s = hp->h_aliases[i++])
287 			    {
288 				sprintf(uhost, "%s@%s", cptr->username, s);
289 				if (match(tmp->host, uhost) == 0)
290 					return tmp;
291 			    }
292 		sprintf(uhost, "%s@%s", cptr->username, cptr->sockhost);
293 		if (match(tmp->host, uhost) == 0)
294 			return tmp;
295 	    }
296 	return aconf;
297 }
298 #endif
299 
300 
301 /*
302 ** m_service
303 **
304 **  <= 2.10 protocol:
305 **	parv[0] = sender prefix
306 **	parv[1] = service name
307 **	parv[2] = server token (unused on pure 2.11 network)
308 **	parv[3] = distribution code
309 **	parv[4] = service type
310 **	parv[5] = hopcount
311 **	parv[6] = info
312 **
313 **  2.11 protocol
314 **	parv[0] = sender prefix
315 **	parv[1] = service name
316 **	parv[2] = distribution mask
317 **	parv[3] = service type
318 **	parv[4]	= info
319 **
320 */
m_service(aClient * cptr,aClient * sptr,int parc,char * parv[])321 int	m_service(aClient *cptr, aClient *sptr, int parc, char *parv[])
322 {
323 	aClient	*acptr = NULL, *bcptr = NULL;
324 	aService *svc;
325 #ifdef  USE_SERVICES
326 	aConfItem *aconf;
327 #endif
328 	aServer	*sp = NULL;
329 	char	*dist, *server = NULL, *info;
330 	int	type, i;
331 
332 	if (sptr->user)
333 	    {
334 		sendto_one(sptr, replies[ERR_ALREADYREGISTRED], ME, BadTo(parv[0]));
335 		return 1;
336 	    }
337 
338 	if (parc < 5)
339 	{
340 		sendto_one(cptr, replies[ERR_NEEDMOREPARAMS], ME,
341 			   BadTo(parv[0]), "SERVICE");
342 		return 1;
343 	}
344 
345 	/* Copy parameters into better documenting variables */
346 	dist = parv[2];
347 	type = strtol(parv[3], NULL, 0);
348 	info = parv[4];
349 
350 	/*
351 	 * Change the sender's origin.
352 	 */
353 	if (IsServer(cptr))
354 	    {
355 		acptr = make_client(cptr);
356 		svc = make_service(acptr);
357 		add_client_to_list(acptr);
358 		strncpyzt(acptr->service->namebuf, parv[1],
359 			sizeof(acptr->service->namebuf));
360 
361 		/* 2.11 protocol - :SID SERVICE ..
362 		 * - we know that the sptr contains the correct server */
363 		acptr->hopcount = sptr->hopcount;
364 		sp = sptr->serv;
365 
366 		if (sp == NULL)
367 		{
368 			sendto_flag(SCH_ERROR,
369                        	    "ERROR: SERVICE:%s without SERVER:%s from %s",
370 				    acptr->name, server,
371 				    get_client_name(cptr, FALSE));
372 			return exit_client(NULL, acptr, &me, "No Such Server");
373 		}
374 		if (match(dist, ME) && match(dist, me.serv->sid))
375 		{
376 			sendto_flag(SCH_ERROR,
377                        	    "ERROR: SERVICE:%s DIST:%s from %s", acptr->name,
378 				    dist, get_client_name(cptr, FALSE));
379 			return exit_client(NULL, acptr, &me,
380 					   "Distribution code mismatch");
381 		}
382 	    }
383 #ifndef	USE_SERVICES
384 	else
385 	    {
386 		sendto_one(cptr, "ERROR :Server doesn't support services");
387 		return 1;
388 	    }
389 #endif
390 
391 
392 #ifdef	USE_SERVICES
393 	if (!IsServer(cptr))
394 	    {
395 		char **isup = isupport;
396 
397 		svc = make_service(sptr);
398 		sptr->hopcount = 0;
399 		server = ME;
400 		sp = me.serv;
401 		if (!do_nick_name(parv[1], 0))
402 		    {
403 			sendto_one(sptr, replies[ERR_ERRONEOUSNICKNAME],
404 				   ME, BadTo(parv[0]), parv[1]);
405 			return 1;
406 		    }
407 		if (strlen(parv[1]) + strlen(server) + 2 >= (size_t) HOSTLEN)
408 		    {
409 			sendto_one(acptr, "ERROR :Servicename is too long.");
410 			sendto_flag(SCH_ERROR,
411 				    "Access for service %d (%s) denied (%s)",
412 				    type, parv[1], "servicename too long");
413 			return exit_client(cptr, sptr, &me, "Name too long");
414 		    }
415 
416 		strncpyzt(sptr->service->namebuf, parv[1],
417 			sizeof(sptr->service->namebuf));
418 		if (!(aconf = find_conf_service(sptr, type, NULL)))
419 		    {
420 			sendto_one(sptr,
421 				   "ERROR :Access denied (service %d) %s",
422 				   type, get_client_name(sptr, TRUE));
423 			sendto_flag(SCH_ERROR,
424 				    "Access denied (service %d) %s", type,
425 				    get_client_name(sptr, TRUE));
426 			return exit_client(cptr, sptr, &me, "Not enabled");
427 		    }
428 
429 		if (!BadPtr(aconf->passwd) &&
430 		    !StrEq(aconf->passwd, sptr->passwd))
431 		    {
432 			sendto_flag(SCH_ERROR,
433 				    "Access denied: (passwd mismatch) %s",
434 				    get_client_name(sptr, TRUE));
435 			return exit_client(cptr, sptr, &me, "Bad Password");
436 		    }
437 
438 		(void)strcat(sptr->name, "@"), strcat(sptr->name, server);
439 		if (find_service(sptr->name, NULL))
440 		    {
441 			sendto_flag(SCH_ERROR, "Service %s already exists",
442 				    get_client_name(sptr, TRUE));
443 			return exit_client(cptr, sptr, &me, "Service Exists");
444 		    }
445 		attach_conf(sptr, aconf);
446 		sendto_one(sptr, replies[RPL_YOURESERVICE], ME, BadTo(sptr->name),
447 			   sptr->name);
448 		sendto_one(sptr, replies[RPL_YOURHOST], ME, BadTo(sptr->name),
449                            get_client_name(&me, FALSE), version);
450 		while (*isup)
451 		{
452 			sendto_one(sptr,replies[RPL_ISUPPORT], ME,
453 			BadTo(sptr->name), *isup);
454 			isup++;
455 		}
456 		sendto_one(sptr, replies[RPL_MYINFO], ME, BadTo(sptr->name), ME, version);
457 		sendto_flag(SCH_NOTICE, "Service %s connected",
458 			    get_client_name(sptr, TRUE));
459 		istat.is_unknown--;
460 		istat.is_myservice++;
461 		if (istat.is_myservice > istat.is_m_myservice)
462 			istat.is_m_myservice = istat.is_myservice;
463 
464 		/* local service, assign to acptr so we can use it later*/
465 		acptr = sptr;
466 	    }
467 #endif
468 
469 	istat.is_service++;
470 	if (istat.is_service > istat.is_m_service)
471 		istat.is_m_service = istat.is_service;
472 	SetService(acptr);
473 	svc->servp = sp;
474 	sp->refcnt++;
475 	svc->server = mystrdup(sp->bcptr->name);
476 	strncpyzt(svc->dist, dist, HOSTLEN);
477 	if (acptr->info != DefInfo)
478 		MyFree(acptr->info);
479 	if (strlen(info) > REALLEN) info[REALLEN] = '\0';
480 	acptr->info = mystrdup(info);
481 	svc->wants = 0;
482 	svc->type = type;
483 	reorder_client_in_list(acptr);
484 	(void)add_to_client_hash_table(acptr->name, acptr);
485 
486 #ifdef	USE_SERVICES
487 	check_services_butone(SERVICE_WANT_SERVICE, NULL, acptr,
488 			      ":%s SERVICE %s %s %d :%s",
489 			      sp->sid, acptr->name, dist, type, info);
490 #endif
491 	sendto_flag(SCH_SERVICE,
492 			"Received SERVICE %s from %s via %s (%s %d %s)",
493 			acptr->name, sptr->name, get_client_name(cptr, TRUE),
494 			dist, acptr->hopcount, info);
495 
496 	for (i = fdas.highest; i >= 0; i--)
497 	{
498 		if (!(bcptr = local[fdas.fd[i]]) || !IsServer(bcptr) ||
499 		    bcptr == cptr)
500 			continue;
501 		if (match(dist, bcptr->name) && match(dist, bcptr->serv->sid))
502 			continue;
503 
504 		sendto_one(bcptr, ":%s SERVICE %s %s %d :%s",
505 				sp->sid, acptr->name, dist, type, info);
506 	}
507 
508 	return 0;
509 }
510 
511 
512 /*
513 ** Returns list of all matching services.
514 ** parv[1] - string to match names against
515 ** parv[2] - type of service
516 */
m_servlist(aClient * cptr,aClient * sptr,int parc,char * parv[])517 int	m_servlist(aClient *cptr, aClient *sptr, int parc, char *parv[])
518 {
519 	Reg	aService *sp;
520 	Reg	aClient *acptr;
521 	char	*mask = BadPtr(parv[1]) ? "*" : parv[1];
522 	int	type = 0;
523 
524 	if (parc > 2)
525 		type = BadPtr(parv[2]) ? 0 : strtol(parv[2], NULL, 0);
526 	for (sp = svctop; sp; sp = sp->nexts)
527 		if  ((acptr = sp->bcptr) && (!type || type == sp->type) &&
528 		     (match(mask, acptr->name) == 0))
529 			sendto_one(sptr, replies[RPL_SERVLIST], ME, BadTo(parv[0]),
530 				   acptr->name, sp->server, sp->dist,
531 				   sp->type, acptr->hopcount, acptr->info);
532 	sendto_one(sptr, replies[RPL_SERVLISTEND], ME, BadTo(parv[0]), mask, type);
533 	return 2;
534 }
535 
536 
537 #ifdef	USE_SERVICES
538 /*
539 ** m_servset
540 **
541 **      parv[0] = sender prefix
542 **      parv[1] = data requested
543 **      parv[2] = burst requested (optional)
544 */
m_servset(aClient * cptr,aClient * sptr,int parc,char * parv[])545 int	m_servset(aClient *cptr, aClient *sptr, int parc, char *parv[])
546 {
547 	aClient *acptr;
548 	int burst = 0;
549 
550 	if (!MyConnect(sptr))
551 	    {
552 		sendto_flag(SCH_ERROR, "%s issued a SERVSET (from %s)",
553 			    sptr->name, get_client_name(cptr, TRUE));
554 		return 1;
555 	    }
556 	if (!IsService(sptr) || (IsService(sptr) && sptr->service->wants))
557 	    {
558 		sendto_one(sptr, replies[ERR_NOPRIVILEGES], ME, BadTo(parv[0]));
559 		return 1;
560 	    }
561 	if (sptr->service->wants)
562 		return 1;
563 
564 	/* check against configuration */
565 	sptr->service->wants = strtol(parv[1], NULL, 0) & sptr->service->type;
566 	/* check that service is global for some requests */
567 	if (strcmp(sptr->service->dist, "*"))
568 		sptr->service->wants &= ~SERVICE_MASK_GLOBAL;
569 	/* allow options */
570 	sptr->service->wants |= (strtol(parv[1], NULL, 0) & ~SERVICE_MASK_ALL);
571 	/* send accepted SERVSET */
572 	sendto_one(sptr, ":%s SERVSET %s :%d", sptr->name, sptr->name,
573 		   sptr->service->wants);
574 
575 	if (parc < 3 ||
576 	    ((burst = sptr->service->wants & strtol(parv[2], NULL, 0)) == 0))
577 		return 0;
578 
579 	/*
580 	** services can request a connect burst.
581 	** it is optional, because most services should not need it,
582 	** so let's save some bandwidth.
583 	**
584 	** tokens are NOT used. (2.8.x like burst)
585 	** distribution code is respected.
586 	** service type also respected.
587 	*/
588 	cptr->flags |= FLAGS_CBURST;
589 	if (burst & SERVICE_WANT_SERVER)
590 	    {
591 		int	split;
592 
593 		for (acptr = &me; acptr; acptr = acptr->prev)
594 		    {
595 			if (!IsServer(acptr) && !IsMe(acptr))
596 				continue;
597 			if (match(sptr->service->dist, acptr->name) &&
598 					match(sptr->service->dist, acptr->serv->sid))
599 				continue;
600 			split = (MyConnect(acptr) &&
601 				 mycmp(acptr->name, acptr->sockhost));
602 			sendto_one(sptr, ":%s SERVER %s %d %s :%s",
603 				acptr->serv->up->name, acptr->name,
604 				acptr->hopcount+1,
605 				acptr->serv->sid,
606 				acptr->info);
607 		    }
608 	    }
609 
610 	if (burst & (SERVICE_WANT_NICK|SERVICE_WANT_USER|SERVICE_WANT_SERVICE))
611 	    {
612 		char	buf[BUFSIZE] = "+";
613 
614 		for (acptr = &me; acptr; acptr = acptr->prev)
615 		    {
616 			/* acptr->from == acptr for acptr == cptr */
617 			if (acptr->from == cptr)
618 				continue;
619 			if (IsPerson(acptr))
620 			    {
621 				if (match(sptr->service->dist,
622 					  acptr->user->server) &&
623 					match(sptr->service->dist,
624 					acptr->user->servp->sid))
625 					continue;
626 				if (burst & SERVICE_WANT_UMODE)
627 					send_umode(NULL, acptr, 0, SEND_UMODES,
628 						   buf);
629 				else if (burst & SERVICE_WANT_OPER)
630 					send_umode(NULL, acptr, 0, FLAGS_OPER,
631 						   buf);
632 				sendnum_toone(sptr, burst, acptr, buf);
633 			    }
634 			else if (IsService(acptr))
635 			    {
636 				if (!(burst & SERVICE_WANT_SERVICE))
637 					continue;
638 				if (match(sptr->service->dist,
639 					  acptr->service->server) &&
640 					match(sptr->service->dist,
641 					acptr->service->servp->sid))
642 					continue;
643 				sendto_one(sptr, "SERVICE %s %s %s %d %d :%s",
644 					   acptr->name, acptr->service->server,
645 					   acptr->service->dist,
646 					   acptr->service->type,
647 					   acptr->hopcount + 1, acptr->info);
648 			    }
649 		    }
650 	    }
651 
652 	if (burst & (SERVICE_WANT_CHANNEL|SERVICE_WANT_VCHANNEL|SERVICE_WANT_MODE|SERVICE_WANT_TOPIC))
653 	    {
654 		char    modebuf[MODEBUFLEN], parabuf[MODEBUFLEN];
655 		aChannel	*chptr;
656 
657 		for (chptr = channel; chptr; chptr = chptr->nextch)
658 		    {
659 			if (chptr->users == 0)
660 				continue;
661 			if (burst&(SERVICE_WANT_CHANNEL|SERVICE_WANT_VCHANNEL))
662 				sendto_one(sptr, "CHANNEL %s %d",
663 					   chptr->chname, chptr->users);
664 			if (burst & SERVICE_WANT_MODE)
665 			    {
666 				*modebuf = *parabuf = '\0';
667 				modebuf[1] = '\0';
668 				channel_modes(&me, modebuf, parabuf, chptr);
669 				sendto_one(sptr, "MODE %s %s", chptr->chname,
670 					   modebuf);
671 			    }
672 			if ((burst & SERVICE_WANT_TOPIC) && *chptr->topic)
673 				sendto_one(sptr, "TOPIC %s :%s",
674 					   chptr->chname, chptr->topic);
675 		    }
676 	    }
677 	sendto_one(sptr, "EOB");
678 	cptr->flags ^= FLAGS_CBURST;
679 	return 0;
680 }
681 #endif
682 
683 
684 /*
685 ** Send query to service.
686 ** parv[1] - string to match name against
687 ** parv[2] - string to send to service
688 */
m_squery(aClient * cptr,aClient * sptr,int parc,char * parv[])689 int	m_squery(aClient *cptr, aClient *sptr, int parc, char *parv[])
690 {
691 	aClient *acptr;
692 
693 	if (parc <= 2)
694 	    {
695 		if (parc == 1)
696 			sendto_one(sptr, replies[ERR_NORECIPIENT], ME, BadTo(parv[0]),
697 				   "SQUERY");
698 		else if (parc == 2 || BadPtr(parv[1]))
699 			sendto_one(sptr, replies[ERR_NOTEXTTOSEND], ME, BadTo(parv[0]));
700 		return 1;
701 	    }
702 
703 	if ((acptr = best_service(parv[1], NULL)))
704 		if (MyConnect(acptr) &&
705 		    (acptr->service->wants & SERVICE_WANT_PREFIX))
706 			sendto_one(acptr, ":%s!%s@%s SQUERY %s :%s", parv[0],
707 				   sptr->user->username, sptr->user->host,
708 				   acptr->name, parv[2]);
709 		else if (MyConnect(acptr) &&
710 			(acptr->service->wants & SERVICE_WANT_UID))
711 			sendto_one(acptr, ":%s SQUERY %s :%s", sptr->user->uid,
712 				   acptr->name, parv[2]);
713 		else
714 			sendto_one(acptr, ":%s SQUERY %s :%s",
715 				   parv[0], acptr->name, parv[2]);
716 	else
717 		sendto_one(sptr, replies[ERR_NOSUCHSERVICE], ME, BadTo(parv[0]), parv[1]);
718 	return 2;
719 }
720 
721