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