## Created by Anjuta
SUBDIRS = ltdl \
+ mmatch \
base \
cJSON \
jsonrpc \
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
- <PropertyGroup />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <IncludePath>$(SolutionDir)\mmatch;$(IncludePath)</IncludePath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <IncludePath>$(SolutionDir)\mmatch;$(IncludePath)</IncludePath>
+ </PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
RemoveObject(object);
Objects[object->GetName()] = object;
-
- EventArgs ea;
- ea.Source = object;
- OnObjectCreated(ea);
-
- ConfigHive::Ptr hive = m_Hive.lock();
- if (hive)
- hive->OnObjectCreated(ea);
+ object->Commit();
}
/**
void ForEachObject(function<int (const EventArgs&)> callback);
- Event<EventArgs> OnObjectCreated;
+ Event<EventArgs> OnObjectCommitted;
Event<EventArgs> OnObjectRemoved;
- Event<PropertyChangedEventArgs> OnPropertyChanged;
};
}
void ForEachObject(const string& type,
function<int (const EventArgs&)> callback);
- Event<EventArgs> OnObjectCreated;
+ Event<EventArgs> OnObjectCommitted;
Event<EventArgs> OnObjectRemoved;
- Event<PropertyChangedEventArgs> OnPropertyChanged;
};
}
throw InvalidArgumentException("Config object already has a parent hive.");
m_Hive = hive;
- OnPropertyChanged += bind_weak(&ConfigObject::PropertyChangedHandler, shared_from_this());
}
/**
}
/**
- * PropertyChangedHandler
+ * Commit
*
* Handles changed properties by propagating them to the hive
* and collection this object is contained in.
*
- * @param dpcea The event arguments.
- * @returns 0.
*/
-int ConfigObject::PropertyChangedHandler(const PropertyChangedEventArgs& dpcea)
+void ConfigObject::Commit(void)
{
ConfigHive::Ptr hive = m_Hive.lock();
if (hive) {
- hive->GetCollection(m_Type)->OnPropertyChanged(dpcea);
- hive->OnPropertyChanged(dpcea);
+ EventArgs ea;
+ ea.Source = shared_from_this();
+ hive->GetCollection(m_Type)->OnObjectCommitted(ea);
+ hive->OnObjectCommitted(ea);
}
-
- return 0;
}
string m_Type;
bool m_Replicated;
- int PropertyChangedHandler(const PropertyChangedEventArgs& dpcea);
-
public:
typedef shared_ptr<ConfigObject> Ptr;
typedef weak_ptr<ConfigObject> WeakPtr;
void SetReplicated(bool replicated);
bool GetReplicated(void) const;
+
+ void Commit(void);
};
}
#include "i2-base.h"
+#include <mmatch.h>
using namespace icinga;
return shared_ptr<X509>(cert, X509_free);
}
+
+bool Utility::Match(string pattern, string text)
+{
+ return (match(pattern.c_str(), text.c_str()) != 0);
+}
static shared_ptr<SSL_CTX> MakeSSLContext(string pubkey, string privkey, string cakey);
static string GetCertificateCN(const shared_ptr<X509>& certificate);
static shared_ptr<X509> GetX509Certificate(string pemfile);
+
+ static bool Match(string pattern, string text);
};
}
for (cJSON *property = object->child; property != NULL; property = property->next) {
string key = property->string;
+
+ if (property->type == cJSON_String) {
+ string value = property->valuestring;
- if (property->type != cJSON_String)
- continue;
+ cfgobj->SetPropertyString(key, value);
+ } else if (property->type == cJSON_Array) {
+ Dictionary::Ptr items = make_shared<Dictionary>();
- string value = property->valuestring;
+ for (cJSON *item = property->child; item != NULL; item = item->next) {
+ if (item->type != cJSON_String)
+ continue;
- cfgobj->SetPropertyString(key, value);
+ items->AddUnnamedPropertyString(item->valuestring);
+ }
+
+ cfgobj->SetPropertyDictionary(key, items);
+ }
}
GetApplication()->GetConfigHive()->AddObject(cfgobj);
m_ConfigRpcEndpoint->RegisterMethodHandler("config::FetchObjects",
bind_weak(&ConfigRpcComponent::FetchObjectsHandler, shared_from_this()));
- configHive->OnObjectCreated += bind_weak(&ConfigRpcComponent::LocalObjectCreatedHandler, shared_from_this());
+ configHive->OnObjectCommitted += bind_weak(&ConfigRpcComponent::LocalObjectCommittedHandler, shared_from_this());
configHive->OnObjectRemoved += bind_weak(&ConfigRpcComponent::LocalObjectRemovedHandler, shared_from_this());
- configHive->OnPropertyChanged += bind_weak(&ConfigRpcComponent::LocalPropertyChangedHandler, shared_from_this());
- m_ConfigRpcEndpoint->RegisterMethodSource("config::ObjectCreated");
+ m_ConfigRpcEndpoint->RegisterMethodSource("config::ObjectCommitted");
m_ConfigRpcEndpoint->RegisterMethodSource("config::ObjectRemoved");
- m_ConfigRpcEndpoint->RegisterMethodSource("config::PropertyChanged");
}
endpointManager->OnNewEndpoint += bind_weak(&ConfigRpcComponent::NewEndpointHandler, shared_from_this());
m_ConfigRpcEndpoint->RegisterMethodSource("config::FetchObjects");
- m_ConfigRpcEndpoint->RegisterMethodHandler("config::ObjectCreated",
- bind_weak(&ConfigRpcComponent::RemoteObjectUpdatedHandler, shared_from_this()));
+ m_ConfigRpcEndpoint->RegisterMethodHandler("config::ObjectCommitted",
+ bind_weak(&ConfigRpcComponent::RemoteObjectCommittedHandler, shared_from_this()));
m_ConfigRpcEndpoint->RegisterMethodHandler("config::ObjectRemoved",
bind_weak(&ConfigRpcComponent::RemoteObjectRemovedHandler, shared_from_this()));
- m_ConfigRpcEndpoint->RegisterMethodHandler("config::PropertyChanged",
- bind_weak(&ConfigRpcComponent::RemoteObjectUpdatedHandler, shared_from_this()));
endpointManager->RegisterEndpoint(m_ConfigRpcEndpoint);
}
return 0;
}
-int ConfigRpcComponent::LocalObjectCreatedHandler(const EventArgs& ea)
+int ConfigRpcComponent::LocalObjectCommittedHandler(const EventArgs& ea)
{
ConfigObject::Ptr object = static_pointer_cast<ConfigObject>(ea.Source);
return 0;
}
-int ConfigRpcComponent::LocalPropertyChangedHandler(const PropertyChangedEventArgs& ea)
-{
- ConfigObject::Ptr object = static_pointer_cast<ConfigObject>(ea.Source);
-
- if (!ShouldReplicateObject(object))
- return 0;
-
- JsonRpcRequest msg = MakeObjectMessage(object, "config::PropertyChanged", false);
- Message params;
- msg.SetParams(params);
-
- Message properties;
- params.GetDictionary()->SetPropertyDictionary("properties", properties.GetDictionary());
-
- string value;
- if (!object->GetPropertyString(ea.Property, &value))
- return 0;
-
- properties.GetDictionary()->SetPropertyString(ea.Property, value);
-
- GetEndpointManager()->SendMulticastRequest(m_ConfigRpcEndpoint, msg);
-
- return 0;
-}
-
-int ConfigRpcComponent::RemoteObjectUpdatedHandler(const NewRequestEventArgs& ea)
+int ConfigRpcComponent::RemoteObjectCommittedHandler(const NewRequestEventArgs& ea)
{
JsonRpcRequest message = ea.Request;
bool was_null = false;
int NewEndpointHandler(const NewEndpointEventArgs& ea);
int SessionEstablishedHandler(const EventArgs& ea);
- int LocalObjectCreatedHandler(const EventArgs& ea);
+ int LocalObjectCommittedHandler(const EventArgs& ea);
int LocalObjectRemovedHandler(const EventArgs& ea);
- int LocalPropertyChangedHandler(const PropertyChangedEventArgs& ea);
int FetchObjectsHandler(const NewRequestEventArgs& ea);
- int RemoteObjectUpdatedHandler(const NewRequestEventArgs& ea);
+ int RemoteObjectCommittedHandler(const NewRequestEventArgs& ea);
int RemoteObjectRemovedHandler(const NewRequestEventArgs& ea);
static JsonRpcRequest MakeObjectMessage(const ConfigObject::Ptr& object, string method, bool includeProperties);
GetConfig()->GetPropertyInteger("broker", &isBroker);
m_Broker = (isBroker != 0);
- if (IsBroker()) {
+ m_DiscoveryEndpoint->RegisterMethodSource("discovery::RegisterComponent");
+ m_DiscoveryEndpoint->RegisterMethodHandler("discovery::RegisterComponent",
+ bind_weak(&DiscoveryComponent::RegisterComponentMessageHandler, shared_from_this()));
+
+ if (IsBroker())
m_DiscoveryEndpoint->RegisterMethodSource("discovery::NewComponent");
- m_DiscoveryEndpoint->RegisterMethodHandler("discovery::RegisterComponent",
- bind_weak(&DiscoveryComponent::RegisterComponentMessageHandler, shared_from_this()));
- }
- m_DiscoveryEndpoint->RegisterMethodSource("discovery::RegisterComponent");
m_DiscoveryEndpoint->RegisterMethodHandler("discovery::NewComponent",
bind_weak(&DiscoveryComponent::NewComponentMessageHandler, shared_from_this()));
+
m_DiscoveryEndpoint->RegisterMethodHandler("discovery::Welcome",
bind_weak(&DiscoveryComponent::WelcomeMessageHandler, shared_from_this()));
m_DiscoveryTimer->SetInterval(30);
m_DiscoveryTimer->OnTimerExpired += bind_weak(&DiscoveryComponent::DiscoveryTimerHandler, shared_from_this());
m_DiscoveryTimer->Start();
+
+ /* call the timer as soon as possible */
+ m_DiscoveryTimer->Reschedule(0);
}
/**
{
neea.Endpoint->OnIdentityChanged += bind_weak(&DiscoveryComponent::NewIdentityHandler, shared_from_this());
- if (IsBroker()) {
- /* accept discovery::RegisterComponent messages from any endpoint */
- neea.Endpoint->RegisterMethodSource("discovery::RegisterComponent");
- }
+ /* accept discovery::RegisterComponent messages from any endpoint */
+ neea.Endpoint->RegisterMethodSource("discovery::RegisterComponent");
/* accept discovery::Welcome messages from any endpoint */
neea.Endpoint->RegisterMethodSource("discovery::Welcome");
GetEndpointManager()->ForEachEndpoint(bind(&DiscoveryComponent::CheckExistingEndpoint, this, endpoint, _1));
- ConfigCollection::Ptr brokerCollection = GetApplication()->GetConfigHive()->GetCollection("broker");
- if (brokerCollection->GetObject(identity)) {
- /* accept discovery::NewComponent messages from brokers */
- endpoint->RegisterMethodSource("discovery::NewComponent");
- }
-
// we assume the other component _always_ wants
// discovery::RegisterComponent messages from us
endpoint->RegisterMethodSink("discovery::RegisterComponent");
GetEndpointManager()->SendMulticastRequest(m_DiscoveryEndpoint, request);
}
+bool DiscoveryComponent::HasMessagePermission(Dictionary::Ptr roles, string messageType, string message)
+{
+ ConfigHive::Ptr configHive = GetApplication()->GetConfigHive();
+ ConfigCollection::Ptr roleCollection = configHive->GetCollection("role");
+
+ for (DictionaryIterator ip = roles->Begin(); ip != roles->End(); ip++) {
+ ConfigObject::Ptr role = roleCollection->GetObject(ip->second);
+
+ if (!role)
+ continue;
+
+ Dictionary::Ptr permissions;
+ if (!role->GetPropertyDictionary(messageType, &permissions))
+ continue;
+
+ for (DictionaryIterator is = permissions->Begin(); is != permissions->End(); is++) {
+ if (Utility::Match(is->second.GetString(), message))
+ return true;
+ }
+ }
+
+ return false;
+}
+
/**
* ProcessDiscoveryMessage
*
*
* @param identity The authorative identity of the component.
* @param message The discovery message.
+ * @param trusted Whether the message comes from a trusted source (i.e. a broker).
*/
-void DiscoveryComponent::ProcessDiscoveryMessage(string identity, DiscoveryMessage message)
+void DiscoveryComponent::ProcessDiscoveryMessage(string identity, DiscoveryMessage message, bool trusted)
{
/* ignore discovery messages that are about ourselves */
if (identity == GetEndpointManager()->GetIdentity())
message.GetNode(&info->Node);
message.GetService(&info->Service);
+ ConfigHive::Ptr configHive = GetApplication()->GetConfigHive();
+ ConfigCollection::Ptr endpointCollection = configHive->GetCollection("endpoint");
+
+ ConfigObject::Ptr endpointConfig = endpointCollection->GetObject(identity);
+ Dictionary::Ptr roles;
+ if (endpointConfig)
+ endpointConfig->GetPropertyDictionary("roles", &roles);
+
Message provides;
if (message.GetProvides(&provides)) {
DictionaryIterator i;
for (i = provides.GetDictionary()->Begin(); i != provides.GetDictionary()->End(); i++) {
- if (IsBroker()) {
- /* TODO: Add authorisation checks here */
- }
- info->PublishedMethods.insert(i->second);
+ if (trusted || HasMessagePermission(roles, "publish", i->second))
+ info->PublishedMethods.insert(i->second);
}
}
if (message.GetSubscribes(&subscribes)) {
DictionaryIterator i;
for (i = subscribes.GetDictionary()->Begin(); i != subscribes.GetDictionary()->End(); i++) {
- if (IsBroker()) {
- /* TODO: Add authorisation checks here */
- }
- info->SubscribedMethods.insert(i->second);
+ if (trusted || HasMessagePermission(roles, "subscribe", i->second))
+ info->SubscribedMethods.insert(i->second);
}
}
map<string, ComponentDiscoveryInfo::Ptr>::iterator i;
- i = m_Components.find(identity);
+ i = m_Components.find(identity);
if (i != m_Components.end())
m_Components.erase(i);
if (!message.GetIdentity(&identity))
return 0;
- ProcessDiscoveryMessage(identity, message);
+ ProcessDiscoveryMessage(identity, message, true);
return 0;
}
*/
int DiscoveryComponent::RegisterComponentMessageHandler(const NewRequestEventArgs& nrea)
{
- /* ignore discovery::RegisterComponent messages when we're not a broker */
- if (!IsBroker())
- return 0;
-
DiscoveryMessage message;
nrea.Request.GetParams(&message);
- ProcessDiscoveryMessage(nrea.Sender->GetIdentity(), message);
+ ProcessDiscoveryMessage(nrea.Sender->GetIdentity(), message, false);
return 0;
}
/**
- * BrokerConfigHandler
+ * EndpointConfigHandler
*
- * Processes "broker" config objects.
+ * Processes "endpoint" config objects.
*
* @param ea Event arguments for the new config object.
* @returns 0
*/
-int DiscoveryComponent::BrokerConfigHandler(const EventArgs& ea)
+int DiscoveryComponent::EndpointConfigHandler(const EventArgs& ea)
{
ConfigObject::Ptr object = static_pointer_cast<ConfigObject>(ea.Source);
EndpointManager::Ptr endpointManager = GetEndpointManager();
- /* Check if we're already connected to this broker. */
+ /* Check if we're already connected to this endpoint. */
if (endpointManager->GetEndpointByIdentity(object->GetName()))
return 0;
- string node;
- if (!object->GetPropertyString("node", &node))
- throw InvalidArgumentException("'node' property required for 'broker' config object.");
-
- string service;
- if (!object->GetPropertyString("service", &service))
- throw InvalidArgumentException("'service' property required for 'broker' config object.");
-
- /* reconnect to this broker */
- endpointManager->AddConnection(node, service);
+ string node, service;
+ if (object->GetPropertyString("node", &node) && object->GetPropertyString("service", &service)) {
+ /* reconnect to this endpoint */
+ endpointManager->AddConnection(node, service);
+ }
return 0;
}
time_t now;
time(&now);
- /* check whether we have to reconnect to one of our upstream brokers */
- ConfigCollection::Ptr brokerCollection = GetApplication()->GetConfigHive()->GetCollection("broker");
- brokerCollection->ForEachObject(bind(&DiscoveryComponent::BrokerConfigHandler, this, _1));
+ /* check whether we have to reconnect to one of our upstream endpoints */
+ ConfigCollection::Ptr endpointCollection = GetApplication()->GetConfigHive()->GetCollection("endpoint");
+ endpointCollection->ForEachObject(bind(&DiscoveryComponent::EndpointConfigHandler, this, _1));
map<string, ComponentDiscoveryInfo::Ptr>::iterator i;
for (i = m_Components.begin(); i != m_Components.end(); ) {
int WelcomeMessageHandler(const NewRequestEventArgs& nrea);
void SendDiscoveryMessage(string method, string identity, Endpoint::Ptr recipient);
- void ProcessDiscoveryMessage(string identity, DiscoveryMessage message);
+ void ProcessDiscoveryMessage(string identity, DiscoveryMessage message, bool trusted);
bool GetComponentDiscoveryInfo(string component, ComponentDiscoveryInfo::Ptr *info) const;
void FinishDiscoverySetup(Endpoint::Ptr endpoint);
- int BrokerConfigHandler(const EventArgs& ea);
+ int EndpointConfigHandler(const EventArgs& ea);
+
+ bool HasMessagePermission(Dictionary::Ptr roles, string messageType, string message);
static const int RegistrationTTL = 300;
icinga/Makefile
icinga-app/Makefile
jsonrpc/Makefile
-
+mmatch/Makefile
])
"privkey": "icinga-c1.key",
"pubkey": "icinga-c1.crt",
"cakey": "ca.crt",
- "node": "10.0.10.3",
+ "node": "10.0.10.14",
"service": "7777"
}
},
},
"host": {
"localhost": { "node": "127.0.0.1" }
+ },
+ "include": {
+ "permissions.conf": { "test": [ "hello", "world" ] }
}
}
\ No newline at end of file
"demo": { "replicate": "0" },
"discovery": { "replicate": "0", "broker": "0" }
},
- "broker": {
- "icinga-c1": { "replicate": "0", "node": "10.0.10.3", "service": "7777" }
+ "endpoint": {
+ "icinga-c1": {
+ "replicate": "0",
+ "node": "10.0.10.14",
+ "service": "7777",
+ "roles": [ "broker", "demo" ]
+ }
+ },
+ "role": {
+ "broker": {
+ "publish": [ "discovery::NewComponent" ]
+ },
+ "demo": {
+ "publish": [ "demo::*" ],
+ "subscribe": [ "demo::*" ]
+ }
}
}
\ No newline at end of file
"demo": { "replicate": "0" },
"discovery": { "replicate": "0", "broker": "0" }
},
- "broker": {
- "icinga-c1": { "replicate": "0", "node": "10.0.10.3", "service": "7777" }
+ "endpoint": {
+ "icinga-c1": {
+ "replicate": "0",
+ "node": "10.0.10.14",
+ "service": "7777",
+ "roles": [ "broker", "demo" ]
+ }
+ },
+ "role": {
+ "broker": {
+ "publish": [ "discovery::NewComponent" ]
+ },
+ "demo": {
+ "publish": [ "demo::*" ],
+ "subscribe": [ "demo::*" ]
+ }
}
}
\ No newline at end of file
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual C++ Express 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "base", "base\base.vcxproj", "{9C92DA90-FD53-43A9-A244-90F2E8AF9677}"
+ ProjectSection(ProjectDependencies) = postProject
+ {19CBCE06-3F5C-479A-BD75-E2AB6215D345} = {19CBCE06-3F5C-479A-BD75-E2AB6215D345}
+ EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jsonrpc", "jsonrpc\jsonrpc.vcxproj", "{8DD52FAC-ECEE-48C2-B266-E7C47ED485F8}"
ProjectSection(ProjectDependencies) = postProject
{C1FC77E1-04A4-481B-A78B-2F7AF489C2F8} = {C1FC77E1-04A4-481B-A78B-2F7AF489C2F8}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mmatch", "mmatch\mmatch.vcxproj", "{19CBCE06-3F5C-479A-BD75-E2AB6215D345}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
{EAD41628-BB96-4F99-9070-8A9676801295}.Debug|Win32.Build.0 = Debug|Win32
{EAD41628-BB96-4F99-9070-8A9676801295}.Release|Win32.ActiveCfg = Release|Win32
{EAD41628-BB96-4F99-9070-8A9676801295}.Release|Win32.Build.0 = Release|Win32
+ {19CBCE06-3F5C-479A-BD75-E2AB6215D345}.Debug|Win32.ActiveCfg = Debug|Win32
+ {19CBCE06-3F5C-479A-BD75-E2AB6215D345}.Debug|Win32.Build.0 = Debug|Win32
+ {19CBCE06-3F5C-479A-BD75-E2AB6215D345}.Release|Win32.ActiveCfg = Release|Win32
+ {19CBCE06-3F5C-479A-BD75-E2AB6215D345}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
/* register handler for 'icinga' config objects */
ConfigCollection::Ptr icingaCollection = GetConfigHive()->GetCollection("icinga");
function<int (const EventArgs&)> NewIcingaConfigHandler = bind_weak(&IcingaApplication::NewIcingaConfigHandler, shared_from_this());
- icingaCollection->OnObjectCreated += NewIcingaConfigHandler;
+ icingaCollection->OnObjectCommitted += NewIcingaConfigHandler;
icingaCollection->ForEachObject(NewIcingaConfigHandler);
icingaCollection->OnObjectRemoved += bind_weak(&IcingaApplication::DeletedIcingaConfigHandler, shared_from_this());
/* register handler for 'component' config objects */
ConfigCollection::Ptr componentCollection = GetConfigHive()->GetCollection("component");
function<int (const EventArgs&)> NewComponentHandler = bind_weak(&IcingaApplication::NewComponentHandler, shared_from_this());
- componentCollection->OnObjectCreated += NewComponentHandler;
+ componentCollection->OnObjectCommitted += NewComponentHandler;
componentCollection->ForEachObject(NewComponentHandler);
componentCollection->OnObjectRemoved += bind_weak(&IcingaApplication::DeletedComponentHandler, shared_from_this());
--- /dev/null
+## Process this file with automake to produce Makefile.in
+
+
+noinst_LTLIBRARIES = \
+ libmmatch.la
+
+libmmatch_la_SOURCES = \
+ mmatch.c \
+ mmatch.h
--- /dev/null
+/*
+ * IRC - Internet Relay Chat, common/match.c
+ * Copyright (C) 1990 Jarkko Oikarinen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: Match.cpp,v 1.2 2005/08/15 10:08:50 shroud23 Exp $
+ */
+
+#include <ctype.h>
+#include "mmatch.h"
+
+#define ToLower tolower
+
+/*
+ * mmatch()
+ *
+ * Written by Run (carlo@runaway.xs4all.nl), 25-10-96
+ *
+ *
+ * From: Carlo Wood <carlo@runaway.xs4all.nl>
+ * Message-Id: <199609021026.MAA02393@runaway.xs4all.nl>
+ * Subject: [C-Com] Analysis for `mmatch' (was: gline4 problem)
+ * To: coder-com@mail.undernet.org (coder committee)
+ * Date: Mon, 2 Sep 1996 12:26:01 +0200 (MET DST)
+ *
+ * We need a new function `mmatch(const char *old_mask, const char *new_mask)'
+ * which returns `true' likewise the current `match' (start with copying it),
+ * but which treats '*' and '?' in `new_mask' differently (not "\*" and "\?" !)
+ * as follows: a '*' in `new_mask' does not match a '?' in `old_mask' and
+ * a '?' in `new_mask' does not match a '\?' in `old_mask'.
+ * And ofcourse... a '*' in `new_mask' does not match a '\*' in `old_mask'...
+ * And last but not least, '\?' and '\*' in `new_mask' now become one character.
+ */
+
+int mmatch(const char *old_mask, const char *new_mask)
+{
+ const char *m = old_mask;
+ const char *n = new_mask;
+ const char *ma = m;
+ const char *na = n;
+ int wild = 0;
+ int mq = 0, nq = 0;
+
+ while (1)
+ {
+ if (*m == '*')
+ {
+ while (*m == '*')
+ m++;
+ wild = 1;
+ ma = m;
+ na = n;
+ }
+
+ if (!*m)
+ {
+ if (!*n)
+ return 0;
+ for (m--; (m > old_mask) && (*m == '?'); m--)
+ ;
+ if ((*m == '*') && (m > old_mask) && (m[-1] != '\\'))
+ return 0;
+ if (!wild)
+ return 1;
+ m = ma;
+
+ /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
+ if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
+ ++na;
+
+ n = ++na;
+ }
+ else if (!*n)
+ {
+ while (*m == '*')
+ m++;
+ return (*m != 0);
+ }
+ if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
+ {
+ m++;
+ mq = 1;
+ }
+ else
+ mq = 0;
+
+ /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
+ if ((*n == '\\') && ((n[1] == '*') || (n[1] == '?')))
+ {
+ n++;
+ nq = 1;
+ }
+ else
+ nq = 0;
+
+/*
+ * This `if' has been changed compared to match() to do the following:
+ * Match when:
+ * old (m) new (n) boolean expression
+ * * any (*m == '*' && !mq) ||
+ * ? any except '*' (*m == '?' && !mq && (*n != '*' || nq)) ||
+ * any except * or ? same as m (!((*m == '*' || *m == '?') && !mq) &&
+ * ToLower(*m) == ToLower(*n) &&
+ * !((mq && !nq) || (!mq && nq)))
+ *
+ * Here `any' also includes \* and \? !
+ *
+ * After reworking the boolean expressions, we get:
+ * (Optimized to use boolean shortcircuits, with most frequently occuring
+ * cases upfront (which took 2 hours!)).
+ */
+ if ((*m == '*' && !mq) ||
+ ((!mq || nq) && ToLower(*m) == ToLower(*n)) ||
+ (*m == '?' && !mq && (*n != '*' || nq)))
+ {
+ if (*m)
+ m++;
+ if (*n)
+ n++;
+ }
+ else
+ {
+ if (!wild)
+ return 1;
+ m = ma;
+
+ /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
+ if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
+ ++na;
+
+ n = ++na;
+ }
+ }
+}
+
+/*
+ * Compare if a given string (name) matches the given
+ * mask (which can contain wild cards: '*' - match any
+ * number of chars, '?' - match any single character.
+ *
+ * return 0, if match
+ * 1, if no match
+ */
+
+/*
+ * match
+ *
+ * Rewritten by Andrea Cocito (Nemesi), November 1998.
+ *
+ */
+
+/****************** Nemesi's match() ***************/
+
+int match(const char *mask, const char *string)
+{
+ const char *m = mask, *s = string;
+ char ch;
+ const char *bm, *bs; /* Will be reg anyway on a decent CPU/compiler */
+
+ /* Process the "head" of the mask, if any */
+ while ((ch = *m++) && (ch != '*'))
+ switch (ch)
+ {
+ case '\\':
+ if (*m == '?' || *m == '*')
+ ch = *m++;
+ default:
+ if (ToLower(*s) != ToLower(ch))
+ return 1;
+ case '?':
+ if (!*s++)
+ return 1;
+ };
+ if (!ch)
+ return *s;
+
+ /* We got a star: quickly find if/where we match the next char */
+got_star:
+ bm = m; /* Next try rollback here */
+ while ((ch = *m++))
+ switch (ch)
+ {
+ case '?':
+ if (!*s++)
+ return 1;
+ case '*':
+ bm = m;
+ continue; /* while */
+ case '\\':
+ if (*m == '?' || *m == '*')
+ ch = *m++;
+ default:
+ goto break_while; /* C is structured ? */
+ };
+break_while:
+ if (!ch)
+ return 0; /* mask ends with '*', we got it */
+ ch = ToLower(ch);
+ if (!*s) /* String is already empty, don't continue */
+ return 1; /* This fixes the #quakenet access denied bug */
+ while (ToLower(*s++) != ch)
+ if (!*s)
+ return 1;
+ bs = s; /* Next try start from here */
+
+ /* Check the rest of the "chunk" */
+ while ((ch = *m++))
+ {
+ switch (ch)
+ {
+ case '*':
+ goto got_star;
+ case '\\':
+ if (*m == '?' || *m == '*')
+ ch = *m++;
+ default:
+ if (ToLower(*s) != ToLower(ch))
+ {
+ /* If we've run out of string, give up */
+ if (!*bs)
+ return 1;
+ m = bm;
+ s = bs;
+ goto got_star;
+ };
+ case '?':
+ if (!*s++)
+ return 1;
+ };
+ };
+ if (*s)
+ {
+ m = bm;
+ s = bs;
+ goto got_star;
+ };
+ return 0;
+}
+
+/*
+ * collapse()
+ * Collapse a pattern string into minimal components.
+ * This particular version is "in place", so that it changes the pattern
+ * which is to be reduced to a "minimal" size.
+ *
+ * (C) Carlo Wood - 6 Oct 1998
+ * Speedup rewrite by Andrea Cocito, December 1998.
+ * Note that this new optimized alghoritm can *only* work in place.
+ */
+
+char *collapse(char *mask)
+{
+ int star = 0;
+ char *m = mask;
+ char *b;
+
+ if (m)
+ {
+ do
+ {
+ if ((*m == '*') && ((m[1] == '*') || (m[1] == '?')))
+ {
+ b = m;
+ do
+ {
+ if (*m == '*')
+ star = 1;
+ else
+ {
+ if (star && (*m != '?'))
+ {
+ *b++ = '*';
+ star = 0;
+ };
+ *b++ = *m;
+ if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
+ *b++ = *++m;
+ };
+ }
+ while (*m++);
+ break;
+ }
+ else
+ {
+ if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
+ m++;
+ };
+ }
+ while (*m++);
+ };
+ return mask;
+}
\ No newline at end of file
--- /dev/null
+#ifndef MMATCH_H
+#define MMATCH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+int mmatch(const char *old_mask, const char *new_mask);
+int match(const char *ma, const char *na);
+char *collapse(char *pattern);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* MMATCH_H */
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="mmatch.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="mmatch.h" />
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{19CBCE06-3F5C-479A-BD75-E2AB6215D345}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>mmatch</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup />
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file