1 #include "NativeFeatureIncludes.h"
2 #if _RAKNET_SUPPORT_LogCommandParser==1
3 
4 #include "LogCommandParser.h"
5 #include "TransportInterface.h"
6 
7 #include <memory.h>
8 
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdarg.h>
12 
13 #include "LinuxStrings.h"
14 
15 #ifdef _MSC_VER
16 #pragma warning( push )
17 #endif
18 
LogCommandParser()19 LogCommandParser::LogCommandParser()
20 {
21 	RegisterCommand(CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS,"Subscribe","[<ChannelName>] - Subscribes to a named channel, or all channels");
22 	RegisterCommand(CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS,"Unsubscribe","[<ChannelName>] - Unsubscribes from a named channel, or all channels");
23 	memset(channelNames,0,sizeof(channelNames));
24 }
~LogCommandParser()25 LogCommandParser::~LogCommandParser()
26 {
27 }
OnCommand(const char * command,unsigned numParameters,char ** parameterList,TransportInterface * transport,SystemAddress systemAddress,const char * originalString)28 bool LogCommandParser::OnCommand(const char *command, unsigned numParameters, char **parameterList, TransportInterface *transport, SystemAddress systemAddress, const char *originalString)
29 {
30 	(void) originalString;
31 
32 	if (strcmp(command, "Subscribe")==0)
33 	{
34 		unsigned channelIndex;
35 		if (numParameters==0)
36 		{
37 			Subscribe(systemAddress, 0);
38 			transport->Send(systemAddress, "Subscribed to all channels.\r\n");
39 		}
40 		else if (numParameters==1)
41 		{
42 			if ((channelIndex=Subscribe(systemAddress, parameterList[0]))!=(unsigned)-1)
43 			{
44 				transport->Send(systemAddress, "You are now subscribed to channel %s.\r\n", channelNames[channelIndex]);
45 			}
46 			else
47 			{
48 				transport->Send(systemAddress, "Cannot find channel %s.\r\n", parameterList[0]);
49 				PrintChannels(systemAddress, transport);
50 			}
51 		}
52 		else
53 		{
54 			transport->Send(systemAddress, "Subscribe takes either 0 or 1 parameters.\r\n");
55 		}
56 	}
57 	else if (strcmp(command, "Unsubscribe")==0)
58 	{
59 		unsigned channelIndex;
60 		if (numParameters==0)
61 		{
62 			Unsubscribe(systemAddress, 0);
63 			transport->Send(systemAddress, "Unsubscribed from all channels.\r\n");
64 		}
65 		else if (numParameters==1)
66 		{
67 			if ((channelIndex=Unsubscribe(systemAddress, parameterList[0]))!=(unsigned)-1)
68 			{
69 				transport->Send(systemAddress, "You are now unsubscribed from channel %s.\r\n", channelNames[channelIndex]);
70 			}
71 			else
72 			{
73 				transport->Send(systemAddress, "Cannot find channel %s.\r\n", parameterList[0]);
74 				PrintChannels(systemAddress, transport);
75 			}
76 		}
77 		else
78 		{
79 			transport->Send(systemAddress, "Unsubscribe takes either 0 or 1 parameters.\r\n");
80 		}
81 	}
82 
83 	return true;
84 }
GetName(void) const85 const char *LogCommandParser::GetName(void) const
86 {
87 	return "Logger";
88 }
SendHelp(TransportInterface * transport,SystemAddress systemAddress)89 void LogCommandParser::SendHelp(TransportInterface *transport, SystemAddress systemAddress)
90 {
91 	transport->Send(systemAddress, "The logger will accept user log data via the Log(...) function.\r\n");
92 	transport->Send(systemAddress, "Each log is associated with a named channel.\r\n");
93 	transport->Send(systemAddress, "You can subscribe to or unsubscribe from named channels.\r\n");
94 	PrintChannels(systemAddress, transport);
95 }
AddChannel(const char * channelName)96 void LogCommandParser::AddChannel(const char *channelName)
97 {
98 	unsigned channelIndex;
99 	channelIndex = GetChannelIndexFromName(channelName);
100 	// Each channel can only be added once.
101 	RakAssert(channelIndex==(unsigned)-1);
102 
103 	unsigned i;
104 	for (i=0; i < 32; i++)
105 	{
106 		if (channelNames[i]==0)
107 		{
108 			// Assuming a persistent static string.
109 			channelNames[i]=channelName;
110 			return;
111 		}
112 	}
113 
114 	// No more available channels - max 32 with this implementation where I save subscribed channels with bit operations
115 	RakAssert(0);
116 }
WriteLog(const char * channelName,const char * format,...)117 void LogCommandParser::WriteLog(const char *channelName, const char *format, ...)
118 {
119 	if (channelName==0 || format==0)
120 		return;
121 
122 	unsigned channelIndex;
123 	channelIndex = GetChannelIndexFromName(channelName);
124 	if (channelIndex==(unsigned)-1)
125 	{
126 		AddChannel(channelName);
127 	}
128 
129 	char text[REMOTE_MAX_TEXT_INPUT];
130 	va_list ap;
131 	va_start(ap, format);
132 	_vsnprintf(text, REMOTE_MAX_TEXT_INPUT, format, ap);
133 	va_end(ap);
134 	text[REMOTE_MAX_TEXT_INPUT-1]=0;
135 
136 	// Make sure that text ends in \r\n
137 	int textLen;
138 	textLen=(int)strlen(text);
139 	if (textLen==0)
140 		return;
141 	if (text[textLen-1]=='\n')
142 	{
143 		text[textLen-1]=0;
144 	}
145 	if (textLen < REMOTE_MAX_TEXT_INPUT-4)
146 		strcat(text, "\r\n");
147 	else
148 	{
149 		text[textLen-3]='\r';
150 		text[textLen-2]='\n';
151 		text[textLen-1]=0;
152 	}
153 
154 	// For each user that subscribes to this channel, send to them.
155 	unsigned i;
156 	for (i=0; i < remoteUsers.Size(); i++)
157 	{
158 		if (remoteUsers[i].channels & (1 << channelIndex))
159 		{
160 			trans->Send(remoteUsers[i].systemAddress, text);
161 		}
162 	}
163 }
PrintChannels(SystemAddress systemAddress,TransportInterface * transport) const164 void LogCommandParser::PrintChannels(SystemAddress systemAddress, TransportInterface *transport) const
165 {
166 	unsigned i;
167 	bool anyChannels=false;
168 	transport->Send(systemAddress, "CHANNELS:\r\n");
169 	for (i=0; i < 32; i++)
170 	{
171 		if (channelNames[i])
172 		{
173 			transport->Send(systemAddress, "%i. %s\r\n", i+1,channelNames[i]);
174 			anyChannels=true;
175 		}
176 	}
177 	if (anyChannels==false)
178 		transport->Send(systemAddress, "None.\r\n");
179 }
OnNewIncomingConnection(SystemAddress systemAddress,TransportInterface * transport)180 void LogCommandParser::OnNewIncomingConnection(SystemAddress systemAddress, TransportInterface *transport)
181 {
182 	(void) systemAddress;
183 	(void) transport;
184 }
OnConnectionLost(SystemAddress systemAddress,TransportInterface * transport)185 void LogCommandParser::OnConnectionLost(SystemAddress systemAddress, TransportInterface *transport)
186 {
187 	(void) transport;
188 	Unsubscribe(systemAddress, 0);
189 }
Unsubscribe(SystemAddress systemAddress,const char * channelName)190 unsigned LogCommandParser::Unsubscribe(SystemAddress systemAddress, const char *channelName)
191 {
192 	unsigned i;
193 	for (i=0; i < remoteUsers.Size(); i++)
194 	{
195 		if (remoteUsers[i].systemAddress==systemAddress)
196 		{
197 			if (channelName==0)
198 			{
199 				// Unsubscribe from all and delete this user.
200 				remoteUsers[i]=remoteUsers[remoteUsers.Size()-1];
201 				remoteUsers.RemoveFromEnd();
202 				return 0;
203 			}
204 			else
205 			{
206 				unsigned channelIndex;
207 				channelIndex = GetChannelIndexFromName(channelName);
208 				if (channelIndex!=(unsigned)-1)
209 				{
210 					remoteUsers[i].channels&=0xFFFF ^ (1<<channelIndex); // Unset this bit
211 				}
212 				return channelIndex;
213 			}
214 		}
215 	}
216 	return (unsigned)-1;
217 }
Subscribe(SystemAddress systemAddress,const char * channelName)218 unsigned LogCommandParser::Subscribe(SystemAddress systemAddress, const char *channelName)
219 {
220 	unsigned i;
221 	unsigned channelIndex=(unsigned)-1;
222 	if (channelName)
223 	{
224 		channelIndex = GetChannelIndexFromName(channelName);
225 		if (channelIndex==(unsigned)-1)
226 			return channelIndex;
227 	}
228 
229 	for (i=0; i < remoteUsers.Size(); i++)
230 	{
231 		if (remoteUsers[i].systemAddress==systemAddress)
232 		{
233 			if (channelName)
234 				remoteUsers[i].channels|=1<<channelIndex; // Set this bit for an existing user
235 			else
236 				remoteUsers[i].channels=0xFFFF;
237 			return channelIndex;
238 		}
239 	}
240 
241 	// Make a new user
242 	SystemAddressAndChannel newUser;
243 	newUser.systemAddress = systemAddress;
244 	if (channelName)
245 		newUser.channels=1<<channelIndex;
246 	else
247 		newUser.channels=0xFFFF;
248 	remoteUsers.Insert(newUser, __FILE__, __LINE__);
249 	return channelIndex;
250 }
GetChannelIndexFromName(const char * channelName)251 unsigned LogCommandParser::GetChannelIndexFromName(const char *channelName)
252 {
253 	unsigned i;
254 	for (i=0; i < 32; i++)
255 	{
256 		if (channelNames[i]==0)
257 			return (unsigned) -1;
258 
259 		if (_stricmp(channelNames[i], channelName)==0)
260 			return i;
261 	}
262 	return (unsigned)-1;
263 }
264 
OnTransportChange(TransportInterface * transport)265 void LogCommandParser::OnTransportChange(TransportInterface *transport)
266 {
267 	// I don't want users to have to pass TransportInterface *transport to Log.
268 	trans=transport;
269 }
270 
271 #ifdef _MSC_VER
272 #pragma warning( pop )
273 #endif
274 
275 #endif // _RAKNET_SUPPORT_*
276