1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2019-2020 Sadie Powell <sadie@witchery.services>
5  *   Copyright (C) 2013-2015 Attila Molnar <attilamolnar@hush.com>
6  *
7  * This file is part of InspIRCd.  InspIRCd is free software: you can
8  * redistribute it and/or modify it under the terms of the GNU General Public
9  * License as published by the Free Software Foundation, version 2.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14  * details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 
21 #pragma once
22 
23 #include "base.h"
24 
25 class CoreExport dynamic_reference_base : public interfacebase, public insp::intrusive_list_node<dynamic_reference_base>
26 {
27  public:
28 	class CaptureHook
29 	{
30 	 public:
31 		/** Called when the target of the dynamic_reference has been acquired
32 		 */
33 		virtual void OnCapture() = 0;
34 	};
35 
36  private:
37 	std::string name;
38 	CaptureHook* hook;
39 	void resolve();
40  protected:
41 	ServiceProvider* value;
42  public:
43 	ModuleRef creator;
44 	dynamic_reference_base(Module* Creator, const std::string& Name);
45 	~dynamic_reference_base();
GetProvider()46 	inline const std::string& GetProvider() const { return name; }
47 	void SetProvider(const std::string& newname);
48 
49 	/** Set handler to call when the target object becomes available
50 	 * @param h Handler to call
51 	 */
SetCaptureHook(CaptureHook * h)52 	void SetCaptureHook(CaptureHook* h) { hook = h; }
53 
54 	void check();
55 	operator bool() const { return (value != NULL); }
56 	static void reset_all();
57 };
58 
check()59 inline void dynamic_reference_base::check()
60 {
61 	if (!value)
62 		throw ModuleException("Dynamic reference to '" + name + "' failed to resolve. Are you missing a module?");
63 }
64 
65 template<typename T>
66 class dynamic_reference : public dynamic_reference_base
67 {
68  public:
dynamic_reference(Module * Creator,const std::string & Name)69 	dynamic_reference(Module* Creator, const std::string& Name)
70 		: dynamic_reference_base(Creator, Name) {}
71 
72 	inline T* operator->()
73 	{
74 		check();
75 		return static_cast<T*>(value);
76 	}
77 
78 	T* operator*()
79 	{
80 		return operator->();
81 	}
82 
83 	const T* operator->() const
84 	{
85 		return static_cast<T*>(value);
86 	}
87 
88 	const T* operator*() const
89 	{
90 		return operator->();
91 	}
92 };
93 
94 template<typename T>
95 class dynamic_reference_nocheck : public dynamic_reference_base
96 {
97  public:
dynamic_reference_nocheck(Module * Creator,const std::string & Name)98 	dynamic_reference_nocheck(Module* Creator, const std::string& Name)
99 		: dynamic_reference_base(Creator, Name) {}
100 
101 	T* operator->()
102 	{
103 		return static_cast<T*>(value);
104 	}
105 
106 	T* operator*()
107 	{
108 		return operator->();
109 	}
110 
111 	const T* operator->() const
112 	{
113 		return static_cast<T*>(value);
114 	}
115 
116 	const T* operator*() const
117 	{
118 		return operator->();
119 	}
120 };
121 
122 class ModeHandler;
123 class ChanModeReference : public dynamic_reference_nocheck<ModeHandler>
124 {
125  public:
ChanModeReference(Module * mod,const std::string & modename)126 	ChanModeReference(Module* mod, const std::string& modename)
127 		: dynamic_reference_nocheck<ModeHandler>(mod, "mode/" + modename) {}
128 };
129 
130 class UserModeReference : public dynamic_reference_nocheck<ModeHandler>
131 {
132  public:
UserModeReference(Module * mod,const std::string & modename)133 	UserModeReference(Module* mod, const std::string& modename)
134 		: dynamic_reference_nocheck<ModeHandler>(mod, "umode/" + modename) {}
135 };
136