1 /*
2  *   IRC - Internet Relay Chat, src/modules/m_names.c
3  *   (C) 2006 The UnrealIRCd Team
4  *
5  *   See file AUTHORS in IRC package for additional names of
6  *   the programmers.
7  *
8  *   This program is free software; you can redistribute it and/or modify
9  *   it under the terms of the GNU General Public License as published by
10  *   the Free Software Foundation; either version 1, or (at your option)
11  *   any later version.
12  *
13  *   This program is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with this program; if not, write to the Free Software
20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22 #include "config.h"
23 #include "struct.h"
24 #include "common.h"
25 #include "sys.h"
26 #include "numeric.h"
27 #include "msg.h"
28 #include "proto.h"
29 #include "channel.h"
30 #include <time.h>
31 #include <sys/stat.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #ifdef _WIN32
36 #include <io.h>
37 #endif
38 #include <fcntl.h>
39 #include "h.h"
40 #ifdef STRIPBADWORDS
41 #include "badwords.h"
42 #endif
43 #ifdef _WIN32
44 #include "version.h"
45 #endif
46 
47 DLLFUNC CMD_FUNC(m_names);
48 
49 #define MSG_NAMES 	"NAMES"
50 #define TOK_NAMES 	"?"
51 
52 ModuleHeader MOD_HEADER(m_names)
53   = {
54 	"m_names",
55 	"$Id$",
56 	"command /names",
57 	"3.2-b8-1",
58 	NULL
59     };
60 
MOD_INIT(m_names)61 DLLFUNC int MOD_INIT(m_names)(ModuleInfo *modinfo)
62 {
63 	CommandAdd(modinfo->handle, MSG_NAMES, TOK_NAMES, m_names, MAXPARA, M_USER|M_SERVER);
64 	MARK_AS_OFFICIAL_MODULE(modinfo);
65 	return MOD_SUCCESS;
66 }
67 
MOD_LOAD(m_names)68 DLLFUNC int MOD_LOAD(m_names)(int module_load)
69 {
70 	return MOD_SUCCESS;
71 }
72 
MOD_UNLOAD(m_names)73 DLLFUNC int MOD_UNLOAD(m_names)(int module_unload)
74 {
75 	return MOD_SUCCESS;
76 }
77 
78 /************************************************************************
79  * m_names() - Added by Jto 27 Apr 1989
80  * 12 Feb 2000 - geesh, time for a rewrite -lucas
81  ************************************************************************/
82 
83 static char buf[BUFSIZE];
84 
85 /*
86 ** m_names
87 **	parv[0] = sender prefix
88 **	parv[1] = channel
89 */
90 #define TRUNCATED_NAMES 64
CMD_FUNC(m_names)91 DLLFUNC CMD_FUNC(m_names)
92 {
93 	int uhnames = (MyConnect(sptr) && SupportUHNAMES(sptr)); // cache UHNAMES support
94 	int bufLen = NICKLEN + (!uhnames ? 0 : (1 + USERLEN + 1 + HOSTLEN));
95 	int  mlen = strlen(me.name) + bufLen + 7;
96 	aChannel *chptr;
97 	aClient *acptr;
98 	int  member;
99 	Member *cm;
100 	int  idx, flag = 1, spos;
101 	char *s, *para = parv[1];
102 	char nuhBuffer[NICKLEN+USERLEN+HOSTLEN+3];
103 
104 
105 	if (parc < 2 || !MyConnect(sptr))
106 	{
107 		sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name,
108 		    parv[0], "*");
109 		return 0;
110 	}
111 
112 	if (parc > 1 &&
113 	    hunt_server_token(cptr, sptr, MSG_NAMES, TOK_NAMES, "%s %s", 2, parc, parv))
114 		return 0;
115 
116 	for (s = para; *s; s++)
117 	{
118 		if (*s == ',')
119 		{
120 			if (strlen(para) > TRUNCATED_NAMES)
121 				para[TRUNCATED_NAMES] = '\0';
122 			sendto_realops("names abuser %s %s",
123 			    get_client_name(sptr, FALSE), para);
124 			sendto_one(sptr, err_str(ERR_TOOMANYTARGETS),
125 			    me.name, sptr->name, "NAMES");
126 			return 0;
127 		}
128 	}
129 
130 	chptr = find_channel(para, (aChannel *)NULL);
131 
132 	if (!chptr || (!ShowChannel(sptr, chptr) && !OPCanSeeSecret(sptr)))
133 	{
134 		sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name,
135 		    parv[0], para);
136 		return 0;
137 	}
138 
139 	/* cache whether this user is a member of this channel or not */
140 	member = IsMember(sptr, chptr);
141 
142 	if (PubChannel(chptr))
143 		buf[0] = '=';
144 	else if (SecretChannel(chptr))
145 		buf[0] = '@';
146 	else
147 		buf[0] = '*';
148 
149 	idx = 1;
150 	buf[idx++] = ' ';
151 	for (s = chptr->chname; *s; s++)
152 		buf[idx++] = *s;
153 	buf[idx++] = ' ';
154 	buf[idx++] = ':';
155 
156 	/* If we go through the following loop and never add anything,
157 	   we need this to be empty, otherwise spurious things from the
158 	   LAST /names call get stuck in there.. - lucas */
159 	buf[idx] = '\0';
160 
161 	spos = idx;		/* starting point in buffer for names! */
162 
163 	for (cm = chptr->members; cm; cm = cm->next)
164 	{
165 		acptr = cm->cptr;
166 		if (IsInvisible(acptr) && !member && !IsNetAdmin(sptr))
167 			continue;
168 		if (chptr->mode.mode & MODE_AUDITORIUM)
169 			if (!is_chan_op(sptr, chptr)
170 			    && !is_chanprot(sptr, chptr)
171 			    && !is_chanowner(sptr, chptr))
172 				if (!(cm->
173 				    flags & (CHFL_CHANOP | CHFL_CHANPROT |
174 				    CHFL_CHANOWNER)) && acptr != sptr)
175 					continue;
176 
177 		if (!SupportNAMESX(sptr))
178 		{
179 			/* Standard NAMES reply */
180 #ifdef PREFIX_AQ
181 			if (cm->flags & CHFL_CHANOWNER)
182 				buf[idx++] = '~';
183 			else if (cm->flags & CHFL_CHANPROT)
184 				buf[idx++] = '&';
185 			else
186 #endif
187 			if (cm->flags & CHFL_CHANOP)
188 				buf[idx++] = '@';
189 			else if (cm->flags & CHFL_HALFOP)
190 				buf[idx++] = '%';
191 			else if (cm->flags & CHFL_VOICE)
192 				buf[idx++] = '+';
193 		} else {
194 			/* NAMES reply with all rights included (NAMESX) */
195 #ifdef PREFIX_AQ
196 			if (cm->flags & CHFL_CHANOWNER)
197 				buf[idx++] = '~';
198 			if (cm->flags & CHFL_CHANPROT)
199 				buf[idx++] = '&';
200 #endif
201 			if (cm->flags & CHFL_CHANOP)
202 				buf[idx++] = '@';
203 			if (cm->flags & CHFL_HALFOP)
204 				buf[idx++] = '%';
205 			if (cm->flags & CHFL_VOICE)
206 				buf[idx++] = '+';
207 		}
208 
209 		if (lifesux || !uhnames) {
210 			s = acptr->name;
211 		} else {
212 			strlcpy(nuhBuffer,
213 			        make_nick_user_host(acptr->name, acptr->user->username, GetHost(acptr)),
214 				bufLen + 1);
215 			s = nuhBuffer;
216 		}
217 		/* 's' is intialized above to point to either acptr->name (normal),
218 		 * or to nuhBuffer (for UHNAMES).
219 		 */
220 		for (; *s; s++)
221 			buf[idx++] = *s;
222 		buf[idx++] = ' ';
223 		buf[idx] = '\0';
224 		flag = 1;
225 		if (mlen + idx + bufLen > BUFSIZE - 7)
226 		{
227 			sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name,
228 			    parv[0], buf);
229 			idx = spos;
230 			flag = 0;
231 		}
232 	}
233 
234 	if (flag)
235 		sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
236 
237 	sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], para);
238 
239 	return 0;
240 
241 }
242