Win32: added handler for Ctrl-C

Removed unused code from the Component class
Added accessor function for Application::Instance
This commit is contained in:
Gunnar Beutner 2012-05-21 12:53:38 +02:00
parent 9beef6446f
commit 1f56d2eb13
32 changed files with 125 additions and 112 deletions

View File

@ -1210,7 +1210,7 @@ SERVER_BASED_SEARCH = NO
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
# generate Latex output.
GENERATE_LATEX = NO
GENERATE_LATEX = YES
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be

View File

@ -25,7 +25,7 @@
using namespace icinga;
Application::Ptr I2_EXPORT Application::Instance;
Application::Ptr I2_EXPORT Application::m_Instance;
/**
* Constructor for the Application class.
@ -74,6 +74,16 @@ Application::~Application(void)
#endif /* _WIN32 */
}
/**
* Retrieves a pointer to the application singleton object.
*
* @returns The application object.
*/
Application::Ptr Application::GetInstance(void)
{
return m_Instance;
}
/**
* Processes events for registered sockets and timers and calls whatever
* handlers have been set up for these events.
@ -246,7 +256,6 @@ Component::Ptr Application::LoadComponent(const string& path,
*/
void Application::RegisterComponent(Component::Ptr component)
{
component->SetApplication(static_pointer_cast<Application>(shared_from_this()));
m_Components[component->GetName()] = component;
component->Start();
@ -418,13 +427,24 @@ void Application::SigIntHandler(int signum)
{
assert(signum == SIGINT);
Application::Instance->Shutdown();
Application::GetInstance()->Shutdown();
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_DFL;
sigaction(SIGINT, &sa, NULL);
}
#else /* _WIN32 */
/**
* Console control handler. Prepares the application for cleanly
* shutting down during the next execution of the event loop.
*/
BOOL WINAPI Application::CtrlHandler(DWORD type)
{
Application::GetInstance()->Shutdown();
SetConsoleCtrlHandler(NULL, FALSE);
return TRUE;
}
#endif /* _WIN32 */
/**
@ -438,17 +458,19 @@ int Application::Run(int argc, char **argv)
{
int result;
assert(!Application::Instance);
Application::Instance = static_pointer_cast<Application>(shared_from_this());
assert(!Application::m_Instance);
Application::m_Instance = static_pointer_cast<Application>(shared_from_this());
#ifndef _WIN32
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = Application::SigIntHandler;
sa.sa_handler = &Application::SigIntHandler;
sigaction(SIGINT, &sa, NULL);
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, NULL);
#else
SetConsoleCtrlHandler(&Application::CtrlHandler, TRUE);
#endif /* _WIN32 */
m_Arguments.clear();
@ -458,12 +480,12 @@ int Application::Run(int argc, char **argv)
if (IsDebugging()) {
result = Main(m_Arguments);
Application::Instance.reset();
Application::m_Instance.reset();
} else {
try {
result = Main(m_Arguments);
} catch (const exception& ex) {
Application::Instance.reset();
Application::m_Instance.reset();
Application::Log("---");
Application::Log("Exception: " + Utility::GetTypeName(ex));

View File

@ -32,7 +32,13 @@ DEFINE_EXCEPTION_CLASS(ComponentLoadException);
* @ingroup base
*/
class I2_BASE_API Application : public Object {
public:
typedef shared_ptr<Application> Ptr;
typedef weak_ptr<Application> WeakPtr;
private:
static Application::Ptr m_Instance;
bool m_ShuttingDown; /**< Whether the application is in the process of
shutting down. */
ConfigHive::Ptr m_ConfigHive; /**< The application's configuration. */
@ -43,6 +49,8 @@ private:
#ifndef _WIN32
static void SigIntHandler(int signum);
#else /* _WIN32 */
static BOOL WINAPI CtrlHandler(DWORD type);
#endif /* _WIN32 */
protected:
@ -50,14 +58,11 @@ protected:
string GetExeDirectory(void) const;
public:
typedef shared_ptr<Application> Ptr;
typedef weak_ptr<Application> WeakPtr;
static Application::Ptr Instance;
Application(void);
~Application(void);
static Application::Ptr GetInstance(void);
int Run(int argc, char **argv);
virtual int Main(const vector<string>& args) = 0;

View File

@ -21,26 +21,6 @@
using namespace icinga;
/**
* Sets the application this component belongs to.
*
* @param application The application.
*/
void Component::SetApplication(const Application::WeakPtr& application)
{
m_Application = application;
}
/**
* Retrieves the application this component belongs to.
*
* @returns The application.
*/
Application::Ptr Component::GetApplication(void) const
{
return m_Application.lock();
}
/**
* Sets the configuration for this component.
*

View File

@ -32,16 +32,12 @@ namespace icinga
class I2_BASE_API Component : public Object
{
private:
Application::WeakPtr m_Application;
ConfigObject::Ptr m_Config;
public:
typedef shared_ptr<Component> Ptr;
typedef weak_ptr<Component> WeakPtr;
void SetApplication(const Application::WeakPtr& application);
Application::Ptr GetApplication(void) const;
void SetConfig(const ConfigObject::Ptr& componentConfig);
ConfigObject::Ptr GetConfig(void) const;

View File

@ -78,6 +78,7 @@ ConfigCollection::Ptr ConfigHive::GetCollection(const string& collection)
/**
* Invokes the specified callback for each object contained in this hive.
*
* @param type The config object type.
* @param callback The callback.
*/
void ConfigHive::ForEachObject(const string& type,

View File

@ -40,9 +40,9 @@ public:
void AddObject(const ConfigObject::Ptr& object);
void RemoveObject(const ConfigObject::Ptr& object);
ConfigObject::Ptr GetObject(const string& collection,
ConfigObject::Ptr GetObject(const string& type,
const string& name = string());
ConfigCollection::Ptr GetCollection(const string& collection);
ConfigCollection::Ptr GetCollection(const string& type);
void ForEachObject(const string& type,
function<int (const EventArgs&)> callback);

View File

@ -44,15 +44,24 @@ public:
typedef weak_ptr<Object> WeakPtr;
};
/**
* Compares a weak pointer with a raw pointer.
*/
template<class T>
struct weak_ptr_eq_raw
struct WeakPtrEqual
{
private:
const void *m_Ref;
public:
weak_ptr_eq_raw(const void *ref) : m_Ref(ref) { }
WeakPtrEqual(const void *ref) : m_Ref(ref) { }
/**
* Compares the two pointers.
*
* @param wref The weak pointer.
* @returns true if the pointers point to the same object, false otherwise.
*/
bool operator()(const weak_ptr<T>& wref) const
{
return (wref.lock().get() == (const T *)m_Ref);

View File

@ -60,7 +60,7 @@ void Socket::Start(void)
*/
void Socket::Stop(void)
{
Sockets.remove_if(weak_ptr_eq_raw<Socket>(this));
Sockets.remove_if(WeakPtrEqual<Socket>(this));
}
/**

View File

@ -161,7 +161,7 @@ void Timer::Start(void)
*/
void Timer::Stop(void)
{
Timers.remove_if(weak_ptr_eq_raw<Timer>(this));
Timers.remove_if(WeakPtrEqual<Timer>(this));
}
/**

View File

@ -42,7 +42,7 @@ void ConfigFileComponent::Start(void)
if (fp.fail())
throw ConfigParserException("Could not open config file");
GetApplication()->Log("Reading config file: " + filename);
GetIcingaApplication()->Log("Reading config file: " + filename);
while (!fp.eof()) {
size_t bufferSize = 1024;
@ -93,7 +93,7 @@ void ConfigFileComponent::Start(void)
}
}
GetApplication()->GetConfigHive()->AddObject(cfgobj);
GetConfigHive()->AddObject(cfgobj);
}
}

View File

@ -73,7 +73,7 @@ int ConfigRpcComponent::NewEndpointHandler(const NewEndpointEventArgs& ea)
int ConfigRpcComponent::SessionEstablishedHandler(const EventArgs& ea)
{
RpcRequest request;
RequestMessage request;
request.SetMethod("config::FetchObjects");
Endpoint::Ptr endpoint = static_pointer_cast<Endpoint>(ea.Source);
@ -82,9 +82,9 @@ int ConfigRpcComponent::SessionEstablishedHandler(const EventArgs& ea)
return 0;
}
RpcRequest ConfigRpcComponent::MakeObjectMessage(const ConfigObject::Ptr& object, string method, bool includeProperties)
RequestMessage ConfigRpcComponent::MakeObjectMessage(const ConfigObject::Ptr& object, string method, bool includeProperties)
{
RpcRequest msg;
RequestMessage msg;
msg.SetMethod(method);
MessagePart params;
@ -121,7 +121,7 @@ int ConfigRpcComponent::FetchObjectsHandler(const NewRequestEventArgs& ea)
if (!ShouldReplicateObject(object))
continue;
RpcRequest request = MakeObjectMessage(object, "config::ObjectCreated", true);
RequestMessage request = MakeObjectMessage(object, "config::ObjectCreated", true);
GetEndpointManager()->SendUnicastMessage(m_ConfigRpcEndpoint, client, request);
}
@ -158,7 +158,7 @@ int ConfigRpcComponent::LocalObjectRemovedHandler(const EventArgs& ea)
int ConfigRpcComponent::RemoteObjectCommittedHandler(const NewRequestEventArgs& ea)
{
RpcRequest message = ea.Request;
RequestMessage message = ea.Request;
bool was_null = false;
MessagePart params;
@ -199,7 +199,7 @@ int ConfigRpcComponent::RemoteObjectCommittedHandler(const NewRequestEventArgs&
int ConfigRpcComponent::RemoteObjectRemovedHandler(const NewRequestEventArgs& ea)
{
RpcRequest message = ea.Request;
RequestMessage message = ea.Request;
MessagePart params;
if (!message.GetParams(&params))

View File

@ -41,7 +41,7 @@ private:
int RemoteObjectCommittedHandler(const NewRequestEventArgs& ea);
int RemoteObjectRemovedHandler(const NewRequestEventArgs& ea);
static RpcRequest MakeObjectMessage(const ConfigObject::Ptr& object,
static RequestMessage MakeObjectMessage(const ConfigObject::Ptr& object,
string method, bool includeProperties);
static bool ShouldReplicateObject(const ConfigObject::Ptr& object);

View File

@ -73,7 +73,7 @@ int DemoComponent::DemoTimerHandler(const TimerEventArgs&)
{
Application::Log("Sending multicast 'hello world' message.");
RpcRequest request;
RequestMessage request;
request.SetMethod("demo::HelloWorld");
EndpointManager::Ptr endpointManager = GetIcingaApplication()->GetEndpointManager();

View File

@ -283,7 +283,7 @@ void DiscoveryComponent::FinishDiscoverySetup(Endpoint::Ptr endpoint)
// we assume the other component _always_ wants
// discovery::Welcome messages from us
endpoint->RegisterSubscription("discovery::Welcome");
RpcRequest request;
RequestMessage request;
request.SetMethod("discovery::Welcome");
GetEndpointManager()->SendUnicastMessage(m_DiscoveryEndpoint, endpoint, request);
@ -306,7 +306,7 @@ void DiscoveryComponent::FinishDiscoverySetup(Endpoint::Ptr endpoint)
*/
void DiscoveryComponent::SendDiscoveryMessage(string method, string identity, Endpoint::Ptr recipient)
{
RpcRequest request;
RequestMessage request;
request.SetMethod(method);
DiscoveryMessage params;
@ -348,7 +348,7 @@ bool DiscoveryComponent::HasMessagePermission(Dictionary::Ptr roles, string mess
if (!roles)
return false;
ConfigHive::Ptr configHive = GetApplication()->GetConfigHive();
ConfigHive::Ptr configHive = GetConfigHive();
ConfigCollection::Ptr roleCollection = configHive->GetCollection("role");
for (DictionaryIterator ip = roles->Begin(); ip != roles->End(); ip++) {
@ -395,7 +395,7 @@ void DiscoveryComponent::ProcessDiscoveryMessage(string identity, DiscoveryMessa
message.GetNode(&info->Node);
message.GetService(&info->Service);
ConfigHive::Ptr configHive = GetApplication()->GetConfigHive();
ConfigHive::Ptr configHive = GetConfigHive();
ConfigCollection::Ptr endpointCollection = configHive->GetCollection("endpoint");
ConfigObject::Ptr endpointConfig = endpointCollection->GetObject(identity);
@ -526,7 +526,7 @@ int DiscoveryComponent::DiscoveryTimerHandler(const TimerEventArgs& tea)
time(&now);
/* check whether we have to reconnect to one of our upstream endpoints */
ConfigCollection::Ptr endpointCollection = GetApplication()->GetConfigHive()->GetCollection("endpoint");
ConfigCollection::Ptr endpointCollection = GetConfigHive()->GetCollection("endpoint");
endpointCollection->ForEachObject(bind(&DiscoveryComponent::EndpointConfigHandler, this, _1));
map<string, ComponentDiscoveryInfo::Ptr>::iterator curr, i;

View File

@ -80,8 +80,8 @@ public:
virtual bool IsLocal(void) const = 0;
virtual bool IsConnected(void) const = 0;
virtual void ProcessRequest(Endpoint::Ptr sender, const RpcRequest& message) = 0;
virtual void ProcessResponse(Endpoint::Ptr sender, const RpcResponse& message) = 0;
virtual void ProcessRequest(Endpoint::Ptr sender, const RequestMessage& message) = 0;
virtual void ProcessResponse(Endpoint::Ptr sender, const ResponseMessage& message) = 0;
virtual void Stop(void) = 0;

View File

@ -203,7 +203,7 @@ void EndpointManager::SendUnicastMessage(Endpoint::Ptr sender,
* @param message The message.
*/
void EndpointManager::SendAnycastMessage(Endpoint::Ptr sender,
const RpcRequest& message)
const RequestMessage& message)
{
throw NotImplementedException();
}
@ -216,7 +216,7 @@ void EndpointManager::SendAnycastMessage(Endpoint::Ptr sender,
* @param message The message.
*/
void EndpointManager::SendMulticastMessage(Endpoint::Ptr sender,
const RpcRequest& message)
const RequestMessage& message)
{
string id;
if (message.GetID(&id))

View File

@ -68,8 +68,8 @@ public:
void UnregisterEndpoint(Endpoint::Ptr endpoint);
void SendUnicastMessage(Endpoint::Ptr sender, Endpoint::Ptr recipient, const MessagePart& message);
void SendAnycastMessage(Endpoint::Ptr sender, const RpcRequest& message);
void SendMulticastMessage(Endpoint::Ptr sender, const RpcRequest& message);
void SendAnycastMessage(Endpoint::Ptr sender, const RequestMessage& message);
void SendMulticastMessage(Endpoint::Ptr sender, const RequestMessage& message);
void ForEachEndpoint(function<int (const NewEndpointEventArgs&)> callback);

View File

@ -23,7 +23,8 @@ using namespace icinga;
IcingaApplication::Ptr IcingaComponent::GetIcingaApplication(void) const
{
return static_pointer_cast<IcingaApplication>(GetApplication());
Application::Ptr application = Application::GetInstance();
return static_pointer_cast<IcingaApplication>(application);
}
EndpointManager::Ptr IcingaComponent::GetEndpointManager(void) const

View File

@ -61,7 +61,7 @@ bool JsonRpcEndpoint::IsConnected(void) const
return (bool)m_Client;
}
void JsonRpcEndpoint::ProcessRequest(Endpoint::Ptr sender, const RpcRequest& message)
void JsonRpcEndpoint::ProcessRequest(Endpoint::Ptr sender, const RequestMessage& message)
{
if (IsConnected()) {
string id;
@ -75,7 +75,7 @@ void JsonRpcEndpoint::ProcessRequest(Endpoint::Ptr sender, const RpcRequest& mes
}
}
void JsonRpcEndpoint::ProcessResponse(Endpoint::Ptr sender, const RpcResponse& message)
void JsonRpcEndpoint::ProcessResponse(Endpoint::Ptr sender, const ResponseMessage& message)
{
if (IsConnected())
m_Client->SendMessage(message);
@ -91,7 +91,7 @@ int JsonRpcEndpoint::NewMessageHandler(const NewMessageEventArgs& nmea)
if (!HasPublication(method))
return 0;
RpcRequest request = message;
RequestMessage request = message;
string id;
if (request.GetID(&id))
@ -99,7 +99,7 @@ int JsonRpcEndpoint::NewMessageHandler(const NewMessageEventArgs& nmea)
else
GetEndpointManager()->SendMulticastMessage(sender, request);
} else {
RpcResponse response = message;
ResponseMessage response = message;
// TODO: deal with response messages
throw NotImplementedException();

View File

@ -58,8 +58,8 @@ public:
virtual bool IsLocal(void) const;
virtual bool IsConnected(void) const;
virtual void ProcessRequest(Endpoint::Ptr sender, const RpcRequest& message);
virtual void ProcessResponse(Endpoint::Ptr sender, const RpcResponse& message);
virtual void ProcessRequest(Endpoint::Ptr sender, const RequestMessage& message);
virtual void ProcessResponse(Endpoint::Ptr sender, const ResponseMessage& message);
virtual void Stop(void);
};

View File

@ -54,7 +54,7 @@ void VirtualEndpoint::UnregisterTopicHandler(string topic, function<int (const N
throw NotImplementedException();
}
void VirtualEndpoint::ProcessRequest(Endpoint::Ptr sender, const RpcRequest& request)
void VirtualEndpoint::ProcessRequest(Endpoint::Ptr sender, const RequestMessage& request)
{
string method;
if (!request.GetMethod(&method))
@ -72,7 +72,7 @@ void VirtualEndpoint::ProcessRequest(Endpoint::Ptr sender, const RpcRequest& req
i->second(nrea);
}
void VirtualEndpoint::ProcessResponse(Endpoint::Ptr sender, const RpcResponse& response)
void VirtualEndpoint::ProcessResponse(Endpoint::Ptr sender, const ResponseMessage& response)
{
// TODO: figure out which request this response belongs to and notify the caller
throw NotImplementedException();

View File

@ -31,7 +31,7 @@ namespace icinga
struct I2_ICINGA_API NewRequestEventArgs : public EventArgs
{
Endpoint::Ptr Sender;
RpcRequest Request;
RequestMessage Request;
};
/**
@ -56,8 +56,8 @@ public:
virtual bool IsLocal(void) const;
virtual bool IsConnected(void) const;
virtual void ProcessRequest(Endpoint::Ptr sender, const RpcRequest& message);
virtual void ProcessResponse(Endpoint::Ptr sender, const RpcResponse& message);
virtual void ProcessRequest(Endpoint::Ptr sender, const RequestMessage& message);
virtual void ProcessResponse(Endpoint::Ptr sender, const ResponseMessage& message);
virtual void Stop(void);
};

View File

@ -14,10 +14,10 @@ libjsonrpc_la_SOURCES = \
messagepart.h \
netstring.cpp \
netstring.h \
rpcrequest.cpp \
rpcrequest.h \
rpcresponse.cpp \
rpcresponse.h
requestmessage.cpp \
requestmessage.h \
responsemessage.cpp \
responsemessage.h
libjsonrpc_la_CXXFLAGS = \
-DI2_JSONRPC_BUILD \

View File

@ -37,8 +37,8 @@
#endif /* I2_JSONRPC_BUILD */
#include "messagepart.h"
#include "rpcrequest.h"
#include "rpcresponse.h"
#include "requestmessage.h"
#include "responsemessage.h"
#include "netstring.h"
#include "jsonrpcclient.h"
#include "jsonrpcserver.h"

View File

@ -13,16 +13,16 @@
<ItemGroup>
<ClInclude Include="i2-jsonrpc.h" />
<ClInclude Include="jsonrpcclient.h" />
<ClInclude Include="rpcrequest.h" />
<ClInclude Include="rpcresponse.h" />
<ClInclude Include="requestmessage.h" />
<ClInclude Include="responsemessage.h" />
<ClInclude Include="jsonrpcserver.h" />
<ClInclude Include="messagepart.h" />
<ClInclude Include="netstring.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="jsonrpcclient.cpp" />
<ClCompile Include="rpcrequest.cpp" />
<ClCompile Include="rpcresponse.cpp" />
<ClCompile Include="requestmessage.cpp" />
<ClCompile Include="responsemessage.cpp" />
<ClCompile Include="jsonrpcserver.cpp" />
<ClCompile Include="messagepart.cpp" />
<ClCompile Include="netstring.cpp" />

View File

@ -4,17 +4,17 @@
<ClCompile Include="jsonrpcclient.cpp" />
<ClCompile Include="jsonrpcserver.cpp" />
<ClCompile Include="netstring.cpp" />
<ClCompile Include="rpcrequest.cpp" />
<ClCompile Include="rpcresponse.cpp" />
<ClCompile Include="messagepart.cpp" />
<ClCompile Include="requestmessage.cpp" />
<ClCompile Include="responsemessage.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="i2-jsonrpc.h" />
<ClInclude Include="jsonrpcclient.h" />
<ClInclude Include="jsonrpcserver.h" />
<ClInclude Include="netstring.h" />
<ClInclude Include="rpcrequest.h" />
<ClInclude Include="rpcresponse.h" />
<ClInclude Include="messagepart.h" />
<ClInclude Include="requestmessage.h" />
<ClInclude Include="responsemessage.h" />
</ItemGroup>
</Project>

View File

@ -145,11 +145,10 @@ string MessagePart::ToJsonString(void) const
char *jsonString;
string result;
#ifdef _DEBUG
jsonString = cJSON_Print(json);
#else /* _DEBUG */
jsonString = cJSON_PrintUnformatted(json);
#endif /* _DEBUG */
if (!Application::GetInstance()->IsDebugging())
jsonString = cJSON_Print(json);
else
jsonString = cJSON_PrintUnformatted(json);
cJSON_Delete(json);

View File

@ -17,8 +17,8 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#ifndef RPCREQUEST_H
#define RPCREQUEST_H
#ifndef REQUESTMESSAGE_H
#define REQUESTMESSAGE_H
namespace icinga
{
@ -28,22 +28,22 @@ namespace icinga
*
* @ingroup jsonrpc
*/
class I2_JSONRPC_API RpcRequest : public MessagePart
class I2_JSONRPC_API RequestMessage : public MessagePart
{
public:
/**
* Constructor for the RpcRequest class.
* Constructor for the RequestMessage class.
*/
RpcRequest(void) : MessagePart() {
RequestMessage(void) : MessagePart() {
SetVersion("2.0");
}
/**
* Copy-constructor for the RpcRequest class.
* Copy-constructor for the RequestMessage class.
*
* @param message The message that is to be copied.
*/
RpcRequest(const MessagePart& message) : MessagePart(message) { }
RequestMessage(const MessagePart& message) : MessagePart(message) { }
/**
* Retrieves the version of the JSON-RPC protocol.
@ -132,4 +132,4 @@ public:
}
#endif /* RPCREQUEST_H */
#endif /* REQUESTMESSAGE_H */

View File

@ -17,8 +17,8 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#ifndef RPCRESPONSE_H
#define RPCRESPONSE_H
#ifndef RESPONSEMESSAGE_H
#define RESPONSEMESSAGE_H
namespace icinga
{
@ -28,22 +28,22 @@ namespace icinga
*
* @ingroup jsonrpc
*/
class I2_JSONRPC_API RpcResponse : public MessagePart
class I2_JSONRPC_API ResponseMessage : public MessagePart
{
public:
/**
* Constructor for the RpcResponse class.
* Constructor for the ResponseMessage class.
*/
RpcResponse(void) : MessagePart() {
ResponseMessage(void) : MessagePart() {
SetVersion("2.0");
}
/**
* Copy-constructor for the RpcResponse class.
* Copy-constructor for the ResponseMessage class.
*
* @param message The message that should be copied.
*/
RpcResponse(const MessagePart& message) : MessagePart(message) { }
ResponseMessage(const MessagePart& message) : MessagePart(message) { }
/**
* Retrieves the version of the JSON-RPC protocol.
@ -132,4 +132,4 @@ public:
}
#endif /* RPCRESPONSE_H */
#endif /* RESPONSEMESSAGE_H */