/*
* (standard BSD license)
*
* Copyright (c) 2002, Chad Myers, et al.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer. Redistributions in binary form
* must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with
* the distribution. Neither the name of SourceForge, nor Microsoft nor the names
* of its contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Diagnostics;
using System.Collections;
using System.Text;
using MSNP;
namespace MSNP.CommandParsers{
/// <summary>
/// Summary description for CommandParser.
/// </summary>
internal class CommandParser
{
private Hashtable m_ParsersTable = new Hashtable();
internal CommandParser()
{
// Populate parser table
IDCommandParser idParser = new IDCommandParser();
NoIDCommandParser noIDParser = new NoIDCommandParser();
MSGCommandParser msgParser = new MSGCommandParser();
ErrorCommandParser errParser = new ErrorCommandParser();
// Response Commands that use a transaction ID
// These are for response only. Some commands use a TID while sending, but not
// during server response, such as MSG
m_ParsersTable.Add(ConnectionHandler.ACK, idParser);
m_ParsersTable.Add(ConnectionHandler.ADD, idParser);
m_ParsersTable.Add(ConnectionHandler.ANS, idParser);
m_ParsersTable.Add(ConnectionHandler.BLP, idParser);
m_ParsersTable.Add(ConnectionHandler.CAL, idParser);
m_ParsersTable.Add(ConnectionHandler.CHG, idParser);
m_ParsersTable.Add(ConnectionHandler.GTC, idParser);
m_ParsersTable.Add(ConnectionHandler.ILN, idParser);
m_ParsersTable.Add(ConnectionHandler.INF, idParser);
m_ParsersTable.Add(ConnectionHandler.IRO, idParser);
m_ParsersTable.Add(ConnectionHandler.LST, idParser);
m_ParsersTable.Add(ConnectionHandler.NAK, idParser);
m_ParsersTable.Add(ConnectionHandler.REM, idParser);
m_ParsersTable.Add(ConnectionHandler.SYN, idParser);
m_ParsersTable.Add(ConnectionHandler.USR, idParser);
m_ParsersTable.Add(ConnectionHandler.VER, idParser);
m_ParsersTable.Add(ConnectionHandler.XFR, idParser);
// Response commands which do not use an ID
m_ParsersTable.Add(ConnectionHandler.BYE, noIDParser);
m_ParsersTable.Add(ConnectionHandler.FLN, noIDParser);
m_ParsersTable.Add(ConnectionHandler.JOI, noIDParser);
m_ParsersTable.Add(ConnectionHandler.MSG, msgParser);
m_ParsersTable.Add(ConnectionHandler.NLN, noIDParser);
m_ParsersTable.Add(ConnectionHandler.OUT, noIDParser);
m_ParsersTable.Add(ConnectionHandler.RNG, noIDParser);
// Error responses
m_ParsersTable.Add(ConnectionHandler.ERR, errParser);
}
internal Response[] ParseResponses(string rawResponse)
{
// Find the end of the string by find the nulls
int nullStart = rawResponse.IndexOf('\0');
if( nullStart > 0 )
{
string trimmedResponse = rawResponse.Substring(0, nullStart);
string[] eachCommand = ResponseSplit(trimmedResponse);
if( eachCommand.Length < 1 && eachCommand[0].Length > 1)
throw new Exception("Invalid response from server: " + rawResponse);
Response[] responses = new Response[eachCommand.Length];
for(int i = 0; i < eachCommand.Length; i++)
{
if(eachCommand[i].Length < 3)
throw new Exception("Server returned invalid command: " + eachCommand[i]);
string curCommand = eachCommand[i].Substring(0, 3);
bool isError = false;
try
{
// If it converts to a number, it's an error
Int32 errorNum = Int32.Parse(curCommand);
// It's a number, so set the error
isError = true;
}
catch{}
ICommandParser parser;
if( isError )
parser = (ICommandParser) m_ParsersTable[ConnectionHandler.ERR];
else
parser = (ICommandParser) m_ParsersTable[curCommand];
responses[i] = parser.ParseResponse(eachCommand[i]);
}
return responses;
}
else
return new Response[0];
}
string[] ResponseSplit(string response)
{
ArrayList responsesList = new ArrayList();
int lastCRLF = 0;
int curCRLF = response.IndexOf("\r\n");
while(curCRLF >= 0)
{
string curResponse = response.Substring(lastCRLF, curCRLF - lastCRLF);
if( curResponse != "" )
{
if( curResponse.StartsWith(ConnectionHandler.MSG) )
{
// Expected MSG format: MSG <name> <friendlyname> <length>\r\n<headers>\r\n\r\n<message>
string[] allParts = curResponse.Split(new char[] {' '}, 4);
if( allParts.Length < 4 )
throw new Exception("Invalid MSG response from server: " + curResponse);
int length = System.Int32.Parse(allParts[3]);
curCRLF = (curCRLF + 2) + length;
curResponse = response.Substring(lastCRLF, curCRLF - lastCRLF);
responsesList.Add(curResponse);
}
else
{
responsesList.Add(curResponse.Trim());
curCRLF += 2;
}
}
lastCRLF = curCRLF;
if( lastCRLF > response.Length )
curCRLF = -1;
else
curCRLF = response.IndexOf("\r\n", lastCRLF);
}
string[] responses = new string[responsesList.Count];
responsesList.CopyTo(responses);
return responses;
}
}
}
|