// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// engine.cpp - IP administration tool engine
//
#include <eikenv.h>
#include "ipadm.h"
#include "engine.h"
#include "uniload.h"
#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
#include <in_sock_internal.h>
#endif
#ifndef __SECURE_DATA__
#define DEFAULT_ROUTES_FILE _L("C:\\Data\\IpAdm\\route.ini")
#else
#define DEFAULT_ROUTES_FILE _L("route.ini")
#endif
LOCAL_C void AppendInterfaceStatus(TDes& buf, const TInt aStatus)
{
switch (aStatus)
{
case EIfPending: buf.Append(_L("PEND ")); break;
case EIfUp: break;
case EIfBusy: buf.Append(_L("BUSY ")); break;
case EIfDown: buf.Append(_L("DOWN ")); break;
default: buf.Append(_L("???? ")); break;
}
}
LOCAL_C void AppendInterfaceName(TDes& buf, const TName& aName)
{
if (aName.Length() > 0)
{
buf.Append(aName);
}
else
{
buf.Append(_L("default"));
}
}
LOCAL_C void AppendRouteType(TDes& buf, const TInt aType)
{
switch (aType)
{
case ERtNormal: buf.Append(_L(" ")); break;
case ERtUser: buf.Append(_L("u ")); break;
case ERtIcmpAdd: buf.Append(_L("- ")); break; // for IPv6, this is ND entry
case ERtIcmpDel: buf.Append(_L("d ")); break;
default: buf.Append(_L("? ")); break;
}
}
LOCAL_C void AppendRouteState(TDes& buf, const TInt aState)
{
switch (aState)
{
case ERtNone: buf.Append(_L("NONE ")); break;
case ERtPending: buf.Append(_L("PEND ")); break;
case ERtBusy: buf.Append(_L("BUSY ")); break;
case ERtReady: break;
case ERtDown: buf.Append(_L("DOWN ")); break;
default: buf.Append(_L("???? ")); break;
}
}
//
//
// Just count the number of rightmost zeroes in an IPv6 address
// and return (128 - count).
//
LOCAL_C TInt MaskLength(const TIp6Addr &aAddr)
{
TInt count = 0;
for (TInt i = sizeof(aAddr.u.iAddr8) / sizeof(aAddr.u.iAddr8[0]); --i >= 0; )
{
if (aAddr.u.iAddr8[i])
{
TUint8 nonZeroByte = aAddr.u.iAddr8[i];
while ((nonZeroByte & 1) == 0)
{
count += 1;
nonZeroByte >>= 1;
}
break;
}
count += 8;
}
return 128-count;
}
LOCAL_C TInt MaskLength(TUint32 aAddr)
{
TInt count = 0;
// obviously, this is "brute force" counting
while (aAddr & 0x80000000)
{
count++;
aAddr <<= 1;
}
return count;
}
// TRawAddr
// *********
// Lightweight internal help class for handling the link layer addresses
//
class TRawAddr : public TSockAddr
{
public:
void Output(TDes& aBuf) const
{
TUint8* p = (TUint8*)UserPtr();
TInt len = ((TSockAddr *)this)->GetUserLen(); //lint !e1773 // it's a kludge but works anyway
aBuf.SetLength(0);
if (len == 0)
return;
if (aBuf.MaxLength() < len * 4)
{
aBuf.Fill('*', aBuf.MaxLength());
return;
}
if (len == 0)
return;
for (;;)
{
aBuf.AppendFormat(_L("%02X"), *p++ & 0xFF);
if (--len == 0)
break;
aBuf.Append(TChar(':'));
}
}
inline static TRawAddr& Cast(const TSockAddr& aAddr)
{
return *((TRawAddr *)&aAddr); //lint !e1773 // standard way to implement Cast
}
inline static TRawAddr& Cast(const TSockAddr* aAddr)
{
return *((TRawAddr *)aAddr); //lint !e1773 // standard way to implement Cast
}
};
//
CIpAdmEngine::~CIpAdmEngine()
{
//
// Ordering is important... Do not close iSS before
// all sockets associated with it have been closed!
//
iFS.Close();
iSS.Close();
}
void CIpAdmEngine::ConstructL()
{
//
// Start Socket Reader activity
//
CheckResultL(_L("Active Scheduler"), CActiveScheduler::Current() == NULL);
CheckResultL(_L("Connect to File server"), iFS.Connect());
CheckResultL(_L("Connect to Socket server"), iSS.Connect());
}
LOCAL_C void AppendIpAddress(TDes &buf, const TDesC &aLabel, const TInetAddr &aAddr, TInt aSkip = 1)
{
if (aSkip && aAddr.IsUnspecified())
return;
TBuf<64> out;
buf.Append(aLabel);
#ifdef HURRICANE_INSOCK
aAddr.Output(out);
#else
aAddr.OutputWithScope(out);
#endif
buf.Append(out);
}
LOCAL_C void AppendRawAddress(TDes &buf, const TDesC &aLabel, const TSockAddr &aAddr)
{
if (aAddr.Family() == KAFUnspec)
return;
TBuf<100> out;
buf.Append(aLabel);
TRawAddr::Cast(aAddr).Output(out);
buf.Append(out);
}
LOCAL_C void AppendIpMask(TDes &buf, const TInetAddr &aAddr)
{
if (aAddr.Family() == KAfInet6)
buf.AppendFormat(_L("/%d"), MaskLength(aAddr.Ip6Address()));
else
buf.AppendFormat(_L("/%d"), MaskLength(aAddr.Address()));
}
void CIpAdmEngine::Show(TInt /*aVersion*/, const TSoInetInterfaceInfo &aInfo)
{
TBuf<1000> buf;
buf = _L("if ");
AppendInterfaceStatus(buf, aInfo.iState);
AppendInterfaceName(buf, aInfo.iName);
AppendIpAddress(buf, _L(" addr="), (const TInetAddr &)aInfo.iAddress, 0);
AppendIpMask(buf, (const TInetAddr &)aInfo.iNetMask);
AppendIpAddress(buf, _L(" bcast="), (const TInetAddr &)aInfo.iBrdAddr);
AppendIpAddress(buf, _L(" gw="), (const TInetAddr &)aInfo.iDefGate);
AppendIpAddress(buf, _L(" ns1="), (const TInetAddr &)aInfo.iNameSer1);
AppendIpAddress(buf, _L(" ns2="), (const TInetAddr &)aInfo.iNameSer2);
AppendRawAddress(buf, _L(" hwa="), aInfo.iHwAddr);
buf.AppendFormat(_L(" Mtu=%d, SM=%d, F=%x"), aInfo.iMtu, aInfo.iSpeedMetric, (TUint)aInfo.iFeatures);
ShowText(buf);
}
void CIpAdmEngine::Show(TInt /*aVersion*/, const TSoInetRouteInfo &aInfo)
{
TBuf<1000> buf;
buf = _L("rt");
AppendRouteType(buf, aInfo.iType);
AppendRouteState(buf, aInfo.iState);
AppendIpAddress(buf, _L(""), (const TInetAddr &)aInfo.iDstAddr, 0);
AppendIpMask(buf, (const TInetAddr &)aInfo.iNetMask);
// the iIfAddr is actually the src address to be used for this route destination
AppendIpAddress(buf, _L(" src="), (const TInetAddr &)aInfo.iIfAddr);
if (aInfo.iGateway.Family() == KAfInet6 || aInfo.iGateway.Family() == KAfInet)
AppendIpAddress(buf, _L(" gw="), (const TInetAddr &)aInfo.iGateway);
else
AppendRawAddress(buf, _L(" hwa="), aInfo.iGateway);
buf.AppendFormat(_L(" M=%d"), aInfo.iMetric);
ShowText(buf);
}
void CIpAdmEngine::ListInterfaces(TInt aVersion, const TDesC &aProtocol)
{
RSocket socket;
if (CheckResult(aProtocol, socket.Open(iSS, aProtocol)) != KErrNone)
return;
if (socket.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl) == KErrNone)
{
TPckgBuf<TSoInetInterfaceInfo> opt;
while (socket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, opt) == KErrNone)
Show(aVersion, opt());
}
socket.Close();
}
void CIpAdmEngine::ListRoutes(TInt aVersion, const TDesC &aProtocol)
{
RSocket socket;
if (CheckResult(aProtocol, socket.Open(iSS, aProtocol)) != KErrNone)
return;
if (socket.SetOpt(KSoInetEnumRoutes, KSolInetRtCtrl) == KErrNone)
{
TPckgBuf<TSoInetRouteInfo> opt;
while (socket.GetOpt(KSoInetNextRoute, KSolInetRtCtrl, opt) == KErrNone)
Show(aVersion, opt());
}
socket.Close();
}
class TParser : public TLex
{
public:
TParser(const TDesC &aStr);
void NextToken();
int SkipSpaceAndMark();
TInt ParameterValue(const TDesC &aKey, TInt &aValue, const TInt aDefault = 0);
TInt ParameterValue(const TDesC &aKey, TInetAddr &aValue);
TLexMark iLine;
TLexMark iCurrent;
TPtrC iLastLine;
TPtrC Line();
inline void MarkLine() { iCurrent = iLine; iOpen = 1; }
TPtrC iToken;
TInt iOpen;
TInt iFirst; // Non-zero, if next token is first in line
};
#pragma warning (disable:4097)
TParser::TParser(const TDesC &aStr) : TLex(aStr), iLine(), iCurrent(), iLastLine(), iToken(), iOpen(0), iFirst(1)
{
Mark(iLine);
MarkLine();
}
#pragma warning (default:4097)
//
// Return current line as a descriptor
// (and skip to the next line, if not fully parsed)
//
TPtrC TParser::Line()
{
if (iOpen)
{
// Line not fully parsed yet, search to the EOL
while (!Eos())
{
TChar ch = Get();
if (ch == '\n' || ch == '\r')
{
iLastLine.Set(MarkedToken(iCurrent));
iOpen = 0;
Mark(iLine);
break;
}
}
}
return iLastLine;
}
//
// Skip white space and mark, including comments!
//
int TParser::SkipSpaceAndMark()
{
TChar ch;
TInt comment = 0;
TInt newline = 0;
while (!Eos())
{
ch = Get();
if (ch =='\n')
{
comment = 0;
newline = 1;
if (iOpen)
{
iLastLine.Set(MarkedToken(iCurrent));
iOpen = 0;
}
Mark(iLine);
}
else if (comment || ch == '#')
comment = 1;
else if (!ch.IsSpace())
{
UnGet();
break;
}
}
Mark();
return newline;
}
//
// Extract Next token and return
//
void TParser::NextToken()
{
if (SkipSpaceAndMark())
iFirst = 1; // New line!
if (Eos())
{
iFirst = -1;
return;
}
while (!Eos())
{
TChar ch = Peek();
if (ch == '#' || ch.IsSpace())
break;
Inc();
}
iToken.Set(MarkedToken());
iFirst = SkipSpaceAndMark();
}
TInt TParser::ParameterValue(const TDesC &aKey, TInt &aValue, const TInt aDefault)
{
if (aKey.Compare(iToken) != 0)
return KErrNotFound; // Doesn't match, do nothing
//
// When the keyword matches, return is always KErrNone
// (caller must deduce errors by aDefault.
//
if (iFirst)
aValue = aDefault;
else if (Val(aValue) == KErrNone)
iFirst = SkipSpaceAndMark();
else
aValue = aDefault;
return KErrNone;
}
TInt TParser::ParameterValue(const TDesC &aKey, TInetAddr &aValue)
{
if (aKey.Compare(iToken) != 0)
return KErrNotFound; // Doesn't match, do nothing
//
// When the keyword matches, return is always KErrNone
// (caller must deduce errors by aDefault.
//
if (!iFirst)
{
NextToken();
if (aValue.Input(iToken) == KErrNone)
return KErrNone;
}
aValue.SetFamily(0);
return KErrNone;
}
void CIpAdmEngine::AddRoutes(const TDesC &aProtocol)
{
TInt err = KErrNone;
RSocket socket;
if (CheckResult(aProtocol, socket.Open(iSS, aProtocol)) != KErrNone)
return;
HBufC *buf = NULL;
#ifndef __DATA_CAGING__
TRAP(err, buf = UnicodeLoad::LoadL(iFS, DEFAULT_ROUTES_FILE));
if (CheckResult(DEFAULT_ROUTES_FILE, err))
#else // __DATA_CAGING__
// get private path
TFileName filename;
RFs theFS;
theFS.Connect();
theFS.PrivatePath(filename);
theFS.Close();
filename.Append(DEFAULT_ROUTES_FILE);
TRAP(err, buf = UnicodeLoad::LoadL(iFS, filename));
if (CheckResult(filename, err))
#endif // __DATA_CAGING__
{
socket.Close();
return;
}
//lint -save -e613 Trapped above
TParser inifile(*buf); //lint -restore
TInt route_count = 0;
TInt if_count = 0;
while (!err)
{
// Skip until first token in line
while (inifile.iFirst == 0)
inifile.NextToken();
if (inifile.iFirst < 0)
break;
//
// The route file is a simple list of lines with following format
//
inifile.NextToken();
inifile.MarkLine();
if ((inifile.iToken.Compare(_L("route-add")) == 0))
{
// route-add destination netmask metric gateway interface
//
// all except the "metric" are assumed to be addresses
//
TPckgBuf<TSoInetRouteInfo> opt;
opt().iType = ERtUser;
opt().iState = ERtReady;
opt().iIfAddr.SetFamily(KAFUnspec);
for (int i = 0; !err && inifile.iFirst == 0; ++i)
{
switch (i)
{
case 0: // Destination
inifile.NextToken();
err = (TInetAddr::Cast(opt().iDstAddr)).Input(inifile.iToken);
break;
case 1: // Netmask
inifile.NextToken();
err = (TInetAddr::Cast(opt().iNetMask)).Input(inifile.iToken);
break;
case 2: // metric
err = inifile.Val(opt().iMetric);
break;
case 3: // Gateway
inifile.NextToken();
if (inifile.iToken.Compare(_L("-")) == 0)
opt().iGateway.SetFamily(KAFUnspec);
else
err = (TInetAddr::Cast(opt().iGateway)).Input(inifile.iToken);
break;
case 4: // Interface
inifile.NextToken();
if (inifile.iToken.Compare(_L("-")) == 0)
opt().iIfAddr.SetFamily(KAFUnspec);
else
err = (TInetAddr::Cast(opt().iIfAddr)).Input(inifile.iToken);
break;
default:
inifile.NextToken();
break;
}
inifile.SkipSpaceAndMark();
}
if (err)
{
ShowText(_L("Syntax error on line"));
ShowText(inifile.Line());
break;
}
else if (CheckResult(inifile.Line(), socket.SetOpt(KSoInetAddRoute, KSolInetRtCtrl, opt)) == KErrNone)
route_count++;
}
else if ((inifile.iToken.Compare(_L("ifconfig")) == 0))
{
//
// For now only simple format
//
// ifconfig interface [address [remote]] [parameters]
//
// perameters can be
//
// prefix n netmask (ip4)/prefix (ip6) [default 32/128]. This *IS* not same
// as Unix ifconfig. Here the value tells whether a "single address"
// or netmask/prefix configuration is to be performed.
//
// *NOTE* prefix splits the bits in the address into two sections: (prefix,id)
// if prefix part is non-ZERO, it will be added as if router had sent
// RA with prefix option with L=1, A=1
// if id part is non-ZERO, it will be processed as interface id (alias
// keyword will control whether this is primary or additional).
//
// *NOTE* prefix 128 => id part is zero length, assumed ZERO
// prefix 0 => prefix part is zero length, and treated as ZERO
//
// *NOTE* If configuring for single address, do not specify prefix!
//
// alias specify additional network address ([address] required)
// 'alias' is not present, but [address] is, then the primary
// network address is configured.
// delete remove specified network address
// down mark interface down
// up mark interface up
// metric n set metric to n
// mtu n set MTU to n
// ns1 address nameserver 1 address
// ns2 address nameserver 2 address
// proxy speficy address as proxy
// anycast specify address as anycast
//
TPckgBuf<TSoInet6InterfaceInfo> opt;
#if 1
opt().iDoState = 0;
opt().iDoId = 0;
opt().iDoPrefix = 0;
opt().iDoAnycast = 0;
#ifndef HURRICANE_INSOCK
opt().iDoProxy = 0;
#endif
opt().iAlias = 0;
opt().iDelete = 0;
opt().iAddress.SetFamily(0);
opt().iDefGate.SetFamily(0);
opt().iNetMask.SetFamily(0);
opt().iNameSer1.SetFamily(0);
opt().iNameSer2.SetFamily(0);
opt().iMtu = 0;
opt().iSpeedMetric = 0;
#else
// unfortunately, this does not work.. "has initialized data" in MARM compile!
static const TSoInet6InterfaceInfo init_opt;
opt() = init_opt;
#endif
TInt prefix = -1;
for (int i = 0; !err && inifile.iFirst == 0; ++i)
{
inifile.NextToken();
switch (i)
{
case 0: // Interface Name
opt().iName = inifile.iToken;
opt().iTag = inifile.iToken;
break;
case 1: // Address
if ((TInetAddr::Cast(opt().iAddress)).Input(inifile.iToken) != KErrNone)
{
i = 2; // We won't have remote address either!
goto parameters; //lint !e801 // no clean way to do it without goto
}
break;
case 2: // Remote Address
if ((TInetAddr::Cast(opt().iDefGate)).Input(inifile.iToken) == KErrNone)
break;
//lint -fallthrough
default:
parameters:
if (opt().iDoState == 0)
{
if (inifile.iToken.Compare(_L("down")) == 0)
{
opt().iState = EIfDown;
opt().iDoState = 1;
break;
}
if (inifile.iToken.Compare(_L("up")) == 0)
{
opt().iState = EIfUp;
opt().iDoState = 1;
break;
}
}
if (opt().iDoAnycast == 0 &&
#ifndef HURRICANE_INSOCK
opt().iDoProxy == 0 &&
#endif
prefix < 0)
{
// Only one of 'proxy' or 'anycast' can be present. Also, prefix must not
// be present.
if (inifile.iToken.Compare(_L("anycast")) == 0)
{
opt().iDoAnycast = 1;
break;
}
else if (inifile.iToken.Compare(_L("proxy")) == 0)
{
#ifndef HURRICANE_INSOCK
opt().iDoProxy = 1;
#endif
break;
}
}
if (opt().iNameSer1.Family() == 0 && inifile.ParameterValue(_L("ns1"), opt().iNameSer1) == KErrNone)
break;
if (opt().iNameSer2.Family() == 0 && inifile.ParameterValue(_L("ns2"), opt().iNameSer2) == KErrNone)
break;
if (opt().iDelete == 0 && inifile.iToken.Compare(_L("delete")) == 0)
{
opt().iDelete = 1;
break;
}
if (opt().iAlias == 0 && inifile.iToken.Compare(_L("alias")) == 0)
{
opt().iAlias = 1;
break;
}
if (opt().iMtu == 0 && inifile.ParameterValue(_L("mtu"), opt().iMtu) == KErrNone)
break;
if (opt().iSpeedMetric == 0 && inifile.ParameterValue(_L("metric"), opt().iSpeedMetric) == KErrNone)
break;
if (opt().iDoAnycast == 0 &&
#ifndef HURRICANE_INSOCK
opt().iDoProxy == 0 &&
#endif
prefix < 0 &&
inifile.ParameterValue(_L("prefix"), prefix, 129) == KErrNone)
{
// prefix == 129, if value is missing => Error
if (prefix > 128)
err = KErrArgument;
break;
}
err = KErrGeneral;
break;
}
inifile.SkipSpaceAndMark();
}
if (!err)
{
// Munge the prefix information into TSoInet6InterfaceInfo
if (prefix < 0)
{
// No prefix present, iNetMask is left unspecified,
// request "single address" processing (prefix = 128)
opt().iDoId = 1;
opt().iDoPrefix = 1;
}
else if (opt().iAddress.Family() == KAfInet && prefix <= 32)
{
// IPv4 processing -- defines the netmask
const TUint32 mask = ~0UL << (32 - prefix);
const TUint32 addr = opt().iAddress.Address();
TInetAddr::Cast(opt().iNetMask).SetAddress(mask);
if (mask & addr)
opt().iDoPrefix = 1;
if ((~mask) & addr)
opt().iDoId = 1;
}
else if (opt().iAddress.Family() == KAfInet6 && prefix <= 128)
{
// IPv6 processing
TInetAddr p;
// Is Prefix part all zeroes?
p.Prefix(TInetAddr::Cast(opt().iAddress), prefix);
if (!p.Ip6Address().IsUnspecified())
opt().iDoPrefix = 1;
TInetAddr::Cast(opt().iNetMask).PrefixMask(prefix);
// Is Id part all zeroes?
p.SetAddress(TInetAddr::Cast(opt().iAddress).Ip6Address());
const TIp6Addr addr = p.Ip6Address();
const TIp6Addr mask = TInetAddr::Cast(opt().iNetMask).Ip6Address();
if ((addr.u.iAddr32[0] & ~mask.u.iAddr32[0]) != 0 ||
(addr.u.iAddr32[1] & ~mask.u.iAddr32[1]) != 0 ||
(addr.u.iAddr32[2] & ~mask.u.iAddr32[2]) != 0 ||
(addr.u.iAddr32[3] & ~mask.u.iAddr32[3]) != 0)
opt().iDoId = 1;
}
else
{
// incorrect of prefix value
err = KErrArgument;
}
}
if (err)
{
ShowText(_L("Syntax error on line"));
ShowText(inifile.Line());
break;
}
else if (CheckResult(inifile.Line(), socket.SetOpt(KSoInetConfigInterface, KSolInetIfCtrl, opt)) == KErrNone)
if_count++;
}
#ifndef HURRICANE_INSOCK
else if ((inifile.iToken.Compare(_L("setscope")) == 0))
{
//
// For now only simple format
//
// setscope interface interface2 level
//
// perameters can be
//
// interface the name of the interface to be change
// interface2 the name of the interface to used as a source for the scope values
// scope the scope of the join point [2..16]
TPckgBuf<TSoInetIfQuery> opt1;
TPckgBuf<TSoInetIfQuery> opt2;
TInt scope = -1;
TInt i = 0;
for (i = 0; !err && inifile.iFirst == 0; ++i)
{
inifile.NextToken();
switch (i)
{
case 0: // Interface Name (to modify)
opt1().iName = inifile.iToken;
err = CheckResult(inifile.iToken, socket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, opt1));
break;
case 1: // Interface Name (the source)
opt2().iName = inifile.iToken;
err = CheckResult(inifile.iToken, socket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, opt2));
break;
case 2: // Scope Level
err = inifile.ParameterValue(_L("level"), scope);
break;
default:
err = KErrArgument;
break;
}
inifile.SkipSpaceAndMark();
}
if (err || scope < 2 || scope > 16)
{
ShowText(_L("Syntax error on line"));
ShowText(inifile.Line());
break;
}
//
// Build a new scope id vector
//
scope -= 1; // scope array is indexed from 0
#if 0
for (i = 0; ++i < scope;)
opt1().iZone[i] = ~opt1().iZone[0];
for ( ;scope < STATIC_CAST(TInt, sizeof(opt1().iZone) / sizeof(opt1().iZone[0])); ++scope)
opt1().iZone[scope] = opt2().iZone[scope];
#else
opt1().iZone[scope] = opt2().iZone[scope];
#endif
opt1().iIndex = opt1().iZone[0];
err = CheckResult(inifile.Line(), socket.SetOpt(KSoInetIfQuerySetScope, KSolInetIfQuery, opt1));
}
#endif
}
delete buf;
TBuf<80> text;
text.Format(_L("Added %d routes, configured %d interfaces"), route_count, if_count);
ShowText(text);
socket.Close();
}
void CIpAdmEngine::HandleCommandL(TInt aCommand)
{
switch (aCommand)
{
case EIpAdmInterfaces:
ListInterfaces(4,_L("udp"));
// ListInterfaces(6,_L("udp6"));
break;
case EIpAdmRoutes:
ListRoutes(4, _L("udp"));
// ListRoutes(6, _L("udp6"));
break;
case EIpAdmAddRoutes:
AddRoutes(_L("udp"));
break;
default:
break;
}
}
//
// CIpAdmEngine::CheckResult
// Output success or fail message, returns the error code
//
TInt CIpAdmEngine::CheckResult(const TDesC &aText, TInt aResult)
{
if (aResult == KErrNone)
return KErrNone;
TBuf<100> err;
CEikonEnv::Static()->GetErrorText(err, aResult);
TBuf<200> str(aText);
str.AppendFormat(_L(" returned with [%s] "), err.PtrZ());
iAppView->Write(str);
return aResult;
}
//
// CIpAdmEngine::CheckResultL
// Output success or fail message, and Leave if the code is not
// KErrNone.
//
void CIpAdmEngine::CheckResultL(const TDesC &aText, TInt aResult)
{
if (CheckResult(aText, aResult) != KErrNone)
User::Leave(aResult);
}
void CIpAdmEngine::ShowText(const TDesC &aText)
{
iAppView->Write(aText);
}