Author: Isomer <isomer@coders.net>
[ircu2.10.12-pk.git] / ircd / m_names.c
1 /*
2  * IRC - Internet Relay Chat, ircd/m_names.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  * $Id$
24  */
25
26 /*
27  * m_functions execute protocol messages on this server:
28  *
29  *    cptr    is always NON-NULL, pointing to a *LOCAL* client
30  *            structure (with an open socket connected!). This
31  *            identifies the physical socket where the message
32  *            originated (or which caused the m_function to be
33  *            executed--some m_functions may call others...).
34  *
35  *    sptr    is the source of the message, defined by the
36  *            prefix part of the message if present. If not
37  *            or prefix not found, then sptr==cptr.
38  *
39  *            (!IsServer(cptr)) => (cptr == sptr), because
40  *            prefixes are taken *only* from servers...
41  *
42  *            (IsServer(cptr))
43  *                    (sptr == cptr) => the message didn't
44  *                    have the prefix.
45  *
46  *                    (sptr != cptr && IsServer(sptr) means
47  *                    the prefix specified servername. (?)
48  *
49  *                    (sptr != cptr && !IsServer(sptr) means
50  *                    that message originated from a remote
51  *                    user (not local).
52  *
53  *            combining
54  *
55  *            (!IsServer(sptr)) means that, sptr can safely
56  *            taken as defining the target structure of the
57  *            message in this server.
58  *
59  *    *Always* true (if 'parse' and others are working correct):
60  *
61  *    1)      sptr->from == cptr  (note: cptr->from == cptr)
62  *
63  *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
64  *            *cannot* be a local connection, unless it's
65  *            actually cptr!). [MyConnect(x) should probably
66  *            be defined as (x == x->from) --msa ]
67  *
68  *    parc    number of variable parameter strings (if zero,
69  *            parv is allowed to be NULL)
70  *
71  *    parv    a NULL terminated list of parameter pointers,
72  *
73  *                    parv[0], sender (prefix string), if not present
74  *                            this points to an empty string.
75  *                    parv[1]...parv[parc-1]
76  *                            pointers to additional parameters
77  *                    parv[parc] == NULL, *always*
78  *
79  *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
80  *                    non-NULL pointers.
81  */
82 #if 0
83 /*
84  * No need to include handlers.h here the signatures must match
85  * and we don't need to force a rebuild of all the handlers everytime
86  * we add a new one to the list. --Bleep
87  */
88 #include "handlers.h"
89 #endif /* 0 */
90 #include "channel.h"
91 #include "client.h"
92 #include "hash.h"
93 #include "ircd.h"
94 #include "ircd_reply.h"
95 #include "ircd_string.h"
96 #include "msg.h"
97 #include "numeric.h"
98 #include "numnicks.h"
99 #include "s_user.h"
100 #include "send.h"
101
102 #include <assert.h>
103 #include <string.h>
104
105 /*
106  * m_names - generic message handler
107  *
108  * parv[0] = sender prefix
109  * parv[1] = channel
110  */
111 int m_names(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
112 {
113   struct Channel *chptr;
114   struct Client *c2ptr;
115   struct Membership* member;
116   struct Channel *ch2ptr = 0;
117   int idx;
118   int flag;
119   int len;
120   int mlen;
121   int needs_space;
122   char* s;
123   char* para = parc > 1 ? parv[1] : 0;
124   char buf[BUFSIZE];
125
126   if (parc > 2 && hunt_server_cmd(sptr, CMD_NAMES, cptr, 1, "%s %C", 2, parc,
127                                   parv))
128     return 0;
129
130   mlen = strlen(me.name) + 10 + strlen(sptr->name);
131
132   if (EmptyString(para))
133     return 0;
134   else if (*para == '0')
135     *para = '\0';
136   
137   s = strchr(para, ',');
138   if (s) {
139     parv[1] = ++s;
140     m_names(cptr, sptr, parc, parv);
141   }
142   clean_channelname(para);
143   ch2ptr = FindChannel(para);
144
145   /*
146    * First, do all visible channels (public and the one user self is)
147    */
148
149   for (chptr = GlobalChannelList; chptr; chptr = chptr->next)
150   {
151     if ((chptr != ch2ptr) && !EmptyString(para))
152       continue;                 /* -- wanted a specific channel */
153     if (!MyConnect(sptr) && EmptyString(para))
154       continue;
155 #ifndef GODMODE
156     if (!ShowChannel(sptr, chptr))
157       continue;                 /* -- users on this are not listed */
158 #endif
159
160     /* Find users on same channel (defined by chptr) */
161
162     strcpy(buf, "* ");
163     len = strlen(chptr->chname);
164     strcpy(buf + 2, chptr->chname);
165     strcpy(buf + 2 + len, " :");
166
167     if (PubChannel(chptr))
168       *buf = '=';
169     else if (SecretChannel(chptr))
170       *buf = '@';
171     idx = len + 4;
172     flag = 1;
173     needs_space = 0;
174     for (member = chptr->members; member; member = member->next_member)
175     {
176       c2ptr = member->user;
177       if (needs_space) {
178         strcat(buf, " ");
179         idx++;
180       }
181       needs_space=1;
182       if (IsZombie(member))
183       {
184         if (member->user != sptr)
185           continue;
186         else
187         {
188           strcat(buf, "!");
189           idx++;
190         }
191       }
192       else if (IsChanOp(member))
193       {
194         strcat(buf, "@");
195         idx++;
196       }
197       else if (HasVoice(member))
198       {
199         strcat(buf, "+");
200         idx++;
201       }
202       strcat(buf, c2ptr->name);
203       idx += strlen(c2ptr->name) + 1;
204       flag = 1;
205       if (mlen + idx + NICKLEN + 5 > BUFSIZE)
206         /* space, modifier, nick, \r \n \0 */
207       {
208         send_reply(sptr, RPL_NAMREPLY, buf);
209         strcpy(buf, "* ");
210         ircd_strncpy(buf + 2, chptr->chname, len + 1);
211         buf[len + 2] = 0;
212         strcat(buf, " :");
213         if (PubChannel(chptr))
214           *buf = '=';
215         else if (SecretChannel(chptr))
216           *buf = '@';
217         idx = len + 4;
218         flag = 0;
219         needs_space=0;
220       }
221     }
222     if (flag)
223       send_reply(sptr, RPL_NAMREPLY, buf);
224   }
225   if (!EmptyString(para))
226   {
227     send_reply(sptr, RPL_ENDOFNAMES, ch2ptr ? ch2ptr->chname : para);
228     return (1);
229   }
230
231   /* Second, do all non-public, non-secret channels in one big sweep */
232
233   strcpy(buf, "* * :");
234   idx = 5;
235   flag = 0;
236   for (c2ptr = GlobalClientList; c2ptr; c2ptr = c2ptr->next)
237   {
238     struct Channel *ch3ptr;
239     int showflag = 0, secret = 0;
240
241 #ifndef GODMODE
242     if (!IsUser(c2ptr) || (sptr != c2ptr && IsInvisible(c2ptr)))
243 #else
244     if (!IsUser(c2ptr))
245 #endif
246       continue;
247     member = c2ptr->user->channel;
248     /*
249      * Don't show a client if they are on a secret channel or when
250      * they are on a channel sptr is on since they have already
251      * been show earlier. -avalon
252      */
253     while (member)
254     {
255       ch3ptr = member->channel;
256 #ifndef GODMODE
257       if (PubChannel(ch3ptr) || find_channel_member(sptr, ch3ptr))
258 #endif
259         showflag = 1;
260       if (SecretChannel(ch3ptr))
261         secret = 1;
262       member = member->next_channel;
263     }
264     if (showflag)               /* Have we already shown them ? */
265       continue;
266 #ifndef GODMODE
267     if (secret)                 /* On any secret channels ? */
268       continue;
269 #endif
270     strcat(buf, c2ptr->name);
271     strcat(buf, " ");
272     idx += strlen(c2ptr->name) + 1;
273     flag = 1;
274 #ifdef GODMODE
275     {
276       char yxx[6];
277       sprintf_irc(yxx, "%s%s", NumNick(c2ptr));
278       assert(c2ptr == findNUser(yxx));
279       sprintf_irc(buf + strlen(buf), "(%s) ", yxx);
280       idx += 6;
281     }
282 #endif
283 #ifdef GODMODE
284     if (mlen + idx + NICKLEN + 9 > BUFSIZE)
285 #else
286     if (mlen + idx + NICKLEN + 3 > BUFSIZE)     /* space, \r\n\0 */
287 #endif
288     {
289       send_reply(sptr, RPL_NAMREPLY, buf);
290       strcpy(buf, "* * :");
291       idx = 5;
292       flag = 0;
293     }
294   }
295   if (flag)
296     send_reply(sptr, RPL_NAMREPLY, buf);
297   send_reply(sptr, RPL_ENDOFNAMES, "*");
298   return 1;
299   return 0;
300 }
301
302 /*
303  * ms_names - server message handler
304  *
305  * parv[0] = sender prefix
306  * parv[1] = channel
307  */
308 int ms_names(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
309 {
310   struct Channel *chptr;
311   struct Client *c2ptr;
312   struct Membership* member;
313   struct Channel *ch2ptr = 0;
314   int idx, flag, len, mlen;
315   char *s, *para = parc > 1 ? parv[1] : 0;
316   char buf[BUFSIZE];
317
318   if (parc > 2 && hunt_server_cmd(sptr, CMD_NAMES, cptr, 1, "%s %C", 2, parc,
319                                   parv))
320     return 0;
321
322   mlen = strlen(me.name) + 10 + strlen(sptr->name);
323
324   if (!EmptyString(para))
325   {
326     s = strchr(para, ',');
327     if (s)
328     {
329       parv[1] = ++s;
330       m_names(cptr, sptr, parc, parv);
331     }
332     clean_channelname(para);
333     ch2ptr = FindChannel(para);
334   }
335
336   /*
337    * First, do all visible channels (public and the one user self is)
338    */
339
340   for (chptr = GlobalChannelList; chptr; chptr = chptr->next)
341   {
342     if ((chptr != ch2ptr) && !EmptyString(para))
343       continue;                 /* -- wanted a specific channel */
344     if (!MyConnect(sptr) && EmptyString(para))
345       continue;
346 #ifndef GODMODE
347     if (!ShowChannel(sptr, chptr))
348       continue;                 /* -- users on this are not listed */
349 #endif
350
351     /* Find users on same channel (defined by chptr) */
352
353     strcpy(buf, "* ");
354     len = strlen(chptr->chname);
355     strcpy(buf + 2, chptr->chname);
356     strcpy(buf + 2 + len, " :");
357
358     if (PubChannel(chptr))
359       *buf = '=';
360     else if (SecretChannel(chptr))
361       *buf = '@';
362     idx = len + 4;
363     flag = 1;
364     for (member = chptr->members; member; member = member->next_member)
365     {
366       c2ptr = member->user;
367 #ifndef GODMODE
368       if (sptr != c2ptr && IsInvisible(c2ptr) && !find_channel_member(sptr, chptr))
369         continue;
370 #endif
371       if (IsZombie(member))
372       {
373         if (member->user != sptr)
374           continue;
375         else
376         {
377           strcat(buf, "!");
378           idx++;
379         }
380       }
381       else if (IsChanOp(member))
382       {
383         strcat(buf, "@");
384         idx++;
385       }
386       else if (HasVoice(member))
387       {
388         strcat(buf, "+");
389         idx++;
390       }
391       strcat(buf, c2ptr->name);
392       strcat(buf, " ");
393       idx += strlen(c2ptr->name) + 1;
394       flag = 1;
395 #ifdef GODMODE
396       {
397         char yxx[6];
398         sprintf_irc(yxx, "%s%s", NumNick(c2ptr));
399         assert(c2ptr == findNUser(yxx));
400         sprintf_irc(buf + strlen(buf), "(%s) ", yxx);
401         idx += 6;
402       }
403       if (mlen + idx + NICKLEN + 11 > BUFSIZE)
404 #else
405       if (mlen + idx + NICKLEN + 5 > BUFSIZE)
406 #endif
407         /* space, modifier, nick, \r \n \0 */
408       {
409         send_reply(sptr, RPL_NAMREPLY, buf);
410         strcpy(buf, "* ");
411         ircd_strncpy(buf + 2, chptr->chname, len + 1);
412         buf[len + 2] = 0;
413         strcat(buf, " :");
414         if (PubChannel(chptr))
415           *buf = '=';
416         else if (SecretChannel(chptr))
417           *buf = '@';
418         idx = len + 4;
419         flag = 0;
420       }
421     }
422     if (flag)
423       send_reply(sptr, RPL_NAMREPLY, buf);
424   }
425   if (!EmptyString(para))
426   {
427     send_reply(sptr, RPL_ENDOFNAMES, ch2ptr ? ch2ptr->chname : para);
428     return (1);
429   }
430
431   /* Second, do all non-public, non-secret channels in one big sweep */
432
433   strcpy(buf, "* * :");
434   idx = 5;
435   flag = 0;
436   for (c2ptr = GlobalClientList; c2ptr; c2ptr = c2ptr->next)
437   {
438     struct Channel *ch3ptr;
439     int showflag = 0, secret = 0;
440
441 #ifndef GODMODE
442     if (!IsUser(c2ptr) || (sptr != c2ptr && IsInvisible(c2ptr)))
443 #else
444     if (!IsUser(c2ptr))
445 #endif
446       continue;
447     member = c2ptr->user->channel;
448     /*
449      * Don't show a client if they are on a secret channel or when
450      * they are on a channel sptr is on since they have already
451      * been show earlier. -avalon
452      */
453     while (member)
454     {
455       ch3ptr = member->channel;
456 #ifndef GODMODE
457       if (PubChannel(ch3ptr) || find_channel_member(sptr, ch3ptr))
458 #endif
459         showflag = 1;
460       if (SecretChannel(ch3ptr))
461         secret = 1;
462       member = member->next_channel;
463     }
464     if (showflag)               /* Have we already shown them ? */
465       continue;
466 #ifndef GODMODE
467     if (secret)                 /* On any secret channels ? */
468       continue;
469 #endif
470     strcat(buf, c2ptr->name);
471     strcat(buf, " ");
472     idx += strlen(c2ptr->name) + 1;
473     flag = 1;
474 #ifdef GODMODE
475     {
476       char yxx[6];
477       sprintf_irc(yxx, "%s%s", NumNick(c2ptr));
478       assert(c2ptr == findNUser(yxx));
479       sprintf_irc(buf + strlen(buf), "(%s) ", yxx);
480       idx += 6;
481     }
482 #endif
483 #ifdef GODMODE
484     if (mlen + idx + NICKLEN + 9 > BUFSIZE)
485 #else
486     if (mlen + idx + NICKLEN + 3 > BUFSIZE)     /* space, \r\n\0 */
487 #endif
488     {
489       send_reply(sptr, RPL_NAMREPLY, buf);
490       strcpy(buf, "* * :");
491       idx = 5;
492       flag = 0;
493     }
494   }
495   if (flag)
496     send_reply(sptr, RPL_NAMREPLY, buf);
497   send_reply(sptr, RPL_ENDOFNAMES, "*");
498   return 1;
499   return 0;
500 }
501
502
503 #if 0
504 /*
505  * m_names                              - Added by Jto 27 Apr 1989
506  *
507  * parv[0] = sender prefix
508  * parv[1] = channel
509  */
510 int m_names(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
511 {
512   struct Channel *chptr;
513   struct Client *c2ptr;
514   struct Membership* member;
515   struct Channel *ch2ptr = 0;
516   int idx, flag, len, mlen;
517   char *s, *para = parc > 1 ? parv[1] : 0;
518   char buf[BUFSIZE];
519
520   if (parc > 2 && hunt_server(1, cptr, sptr, "%s%s " TOK_NAMES " %s %s", 2, parc, parv)) /* XXX DEAD */
521     return 0;
522
523   mlen = strlen(me.name) + 10 + strlen(sptr->name);
524
525   if (!EmptyString(para))
526   {
527     s = strchr(para, ',');
528     if (s)
529     {
530       parv[1] = ++s;
531       m_names(cptr, sptr, parc, parv);
532     }
533     clean_channelname(para);
534     ch2ptr = FindChannel(para);
535   }
536
537   /*
538    * First, do all visible channels (public and the one user self is)
539    */
540
541   for (chptr = GlobalChannelList; chptr; chptr = chptr->next)
542   {
543     if ((chptr != ch2ptr) && !EmptyString(para))
544       continue;                 /* -- wanted a specific channel */
545     if (!MyConnect(sptr) && EmptyString(para))
546       continue;
547 #ifndef GODMODE
548     if (!ShowChannel(sptr, chptr))
549       continue;                 /* -- users on this are not listed */
550 #endif
551
552     /* Find users on same channel (defined by chptr) */
553
554     strcpy(buf, "* ");
555     len = strlen(chptr->chname);
556     strcpy(buf + 2, chptr->chname);
557     strcpy(buf + 2 + len, " :");
558
559     if (PubChannel(chptr))
560       *buf = '=';
561     else if (SecretChannel(chptr))
562       *buf = '@';
563     idx = len + 4;
564     flag = 1;
565     for (member = chptr->members; member; member = member->next_member)
566     {
567       c2ptr = member->user;
568 #ifndef GODMODE
569       if (sptr != c2ptr && IsInvisible(c2ptr) && !find_channel_member(sptr, chptr))
570         continue;
571 #endif
572       if (IsZombie(member))
573       {
574         if (member->user != sptr)
575           continue;
576         else
577         {
578           strcat(buf, "!");
579           idx++;
580         }
581       }
582       else if (IsChanOp(member))
583       {
584         strcat(buf, "@");
585         idx++;
586       }
587       else if (HasVoice(member))
588       {
589         strcat(buf, "+");
590         idx++;
591       }
592       strcat(buf, c2ptr->name);
593       strcat(buf, " ");
594       idx += strlen(c2ptr->name) + 1;
595       flag = 1;
596 #ifdef GODMODE
597       {
598         char yxx[6];
599         sprintf_irc(yxx, "%s%s", NumNick(c2ptr));
600         assert(c2ptr == findNUser(yxx));
601         sprintf_irc(buf + strlen(buf), "(%s) ", yxx);
602         idx += 6;
603       }
604       if (mlen + idx + NICKLEN + 11 > BUFSIZE)
605 #else
606       if (mlen + idx + NICKLEN + 5 > BUFSIZE)
607 #endif
608         /* space, modifier, nick, \r \n \0 */
609       {
610         sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf); /* XXX DEAD */
611         strcpy(buf, "* ");
612         ircd_strncpy(buf + 2, chptr->chname, len + 1);
613         buf[len + 2] = 0;
614         strcat(buf, " :");
615         if (PubChannel(chptr))
616           *buf = '=';
617         else if (SecretChannel(chptr))
618           *buf = '@';
619         idx = len + 4;
620         flag = 0;
621       }
622     }
623     if (flag)
624       sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf); /* XXX DEAD */
625   }
626   if (!EmptyString(para))
627   {
628     sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], /* XXX DEAD */
629         ch2ptr ? ch2ptr->chname : para);
630     return (1);
631   }
632
633   /* Second, do all non-public, non-secret channels in one big sweep */
634
635   strcpy(buf, "* * :");
636   idx = 5;
637   flag = 0;
638   for (c2ptr = GlobalClientList; c2ptr; c2ptr = c2ptr->next)
639   {
640     struct Channel *ch3ptr;
641     int showflag = 0, secret = 0;
642
643 #ifndef GODMODE
644     if (!IsUser(c2ptr) || (sptr != c2ptr && IsInvisible(c2ptr)))
645 #else
646     if (!IsUser(c2ptr))
647 #endif
648       continue;
649     member = c2ptr->user->channel;
650     /*
651      * Don't show a client if they are on a secret channel or when
652      * they are on a channel sptr is on since they have already
653      * been show earlier. -avalon
654      */
655     while (member)
656     {
657       ch3ptr = member->channel;
658 #ifndef GODMODE
659       if (PubChannel(ch3ptr) || find_channel_member(sptr, ch3ptr))
660 #endif
661         showflag = 1;
662       if (SecretChannel(ch3ptr))
663         secret = 1;
664       member = member->next_channel;
665     }
666     if (showflag)               /* Have we already shown them ? */
667       continue;
668 #ifndef GODMODE
669     if (secret)                 /* On any secret channels ? */
670       continue;
671 #endif
672     strcat(buf, c2ptr->name);
673     strcat(buf, " ");
674     idx += strlen(c2ptr->name) + 1;
675     flag = 1;
676 #ifdef GODMODE
677     {
678       char yxx[6];
679       sprintf_irc(yxx, "%s%s", NumNick(c2ptr));
680       assert(c2ptr == findNUser(yxx));
681       sprintf_irc(buf + strlen(buf), "(%s) ", yxx);
682       idx += 6;
683     }
684 #endif
685 #ifdef GODMODE
686     if (mlen + idx + NICKLEN + 9 > BUFSIZE)
687 #else
688     if (mlen + idx + NICKLEN + 3 > BUFSIZE)     /* space, \r\n\0 */
689 #endif
690     {
691       sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf); /* XXX DEAD */
692       strcpy(buf, "* * :");
693       idx = 5;
694       flag = 0;
695     }
696   }
697   if (flag)
698     sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf); /* XXX DEAD */
699   sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], "*"); /* XXX DEAD */
700   return 1;
701 }
702 #endif /* 0 */
703