1 /*
2  * Copyright (C) 2004-2020 ZNC, see the NOTICE file for details.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ZNC_TEMPLATE_H
18 #define ZNC_TEMPLATE_H
19 
20 #include <znc/zncconfig.h>
21 #include <znc/ZNCString.h>
22 #include <iostream>
23 #include <list>
24 #include <memory>
25 
26 class CTemplate;
27 
28 class CTemplateTagHandler {
29   public:
CTemplateTagHandler()30     CTemplateTagHandler() {}
~CTemplateTagHandler()31     virtual ~CTemplateTagHandler() {}
32 
HandleVar(CTemplate & Tmpl,const CString & sName,const CString & sArgs,CString & sOutput)33     virtual bool HandleVar(CTemplate& Tmpl, const CString& sName,
34                            const CString& sArgs, CString& sOutput) {
35         return false;
36     }
37 
HandleTag(CTemplate & Tmpl,const CString & sName,const CString & sArgs,CString & sOutput)38     virtual bool HandleTag(CTemplate& Tmpl, const CString& sName,
39                            const CString& sArgs, CString& sOutput) {
40         return false;
41     }
42 
HandleIf(CTemplate & Tmpl,const CString & sName,const CString & sArgs,CString & sOutput)43     virtual bool HandleIf(CTemplate& Tmpl, const CString& sName,
44                           const CString& sArgs, CString& sOutput) {
45         return HandleVar(Tmpl, sName, sArgs, sOutput);
46     }
47 
HandleValue(CTemplate & Tmpl,CString & sValue,const MCString & msOptions)48     virtual bool HandleValue(CTemplate& Tmpl, CString& sValue,
49                              const MCString& msOptions) {
50         return false;
51     }
52 
53   private:
54 };
55 class CTemplate;
56 
57 class CTemplateOptions {
58   public:
CTemplateOptions()59     CTemplateOptions()
60         : m_eEscapeFrom(CString::EASCII), m_eEscapeTo(CString::EASCII) {}
61 
~CTemplateOptions()62     virtual ~CTemplateOptions() {}
63 
64     void Parse(const CString& sLine);
65 
66     // Getters
GetEscapeFrom()67     CString::EEscape GetEscapeFrom() const { return m_eEscapeFrom; }
GetEscapeTo()68     CString::EEscape GetEscapeTo() const { return m_eEscapeTo; }
69     // !Getters
70   private:
71     CString::EEscape m_eEscapeFrom;
72     CString::EEscape m_eEscapeTo;
73 };
74 
75 class CTemplateLoopContext {
76   public:
CTemplateLoopContext(unsigned long uFilePos,const CString & sLoopName,bool bReverse,std::vector<CTemplate * > * pRows)77     CTemplateLoopContext(unsigned long uFilePos, const CString& sLoopName,
78                          bool bReverse, std::vector<CTemplate*>* pRows)
79         : m_bReverse(bReverse),
80           m_bHasData(false),
81           m_sName(sLoopName),
82           m_uRowIndex(0),
83           m_uFilePosition(uFilePos),
84           m_pvRows(pRows) {}
85 
~CTemplateLoopContext()86     virtual ~CTemplateLoopContext() {}
87 
88     CTemplateLoopContext(const CTemplateLoopContext&) = default;
89     CTemplateLoopContext& operator=(const CTemplateLoopContext&) = default;
90 
91     // Setters
92     void SetHasData(bool b = true) { m_bHasData = b; }
SetName(const CString & s)93     void SetName(const CString& s) { m_sName = s; }
SetRowIndex(unsigned int u)94     void SetRowIndex(unsigned int u) { m_uRowIndex = u; }
IncRowIndex()95     unsigned int IncRowIndex() { return ++m_uRowIndex; }
DecRowIndex()96     unsigned int DecRowIndex() {
97         if (m_uRowIndex == 0) {
98             return 0;
99         }
100         return --m_uRowIndex;
101     }
SetFilePosition(unsigned int u)102     void SetFilePosition(unsigned int u) { m_uFilePosition = u; }
103     // !Setters
104 
105     // Getters
HasData()106     bool HasData() const { return m_bHasData; }
GetName()107     const CString& GetName() const { return m_sName; }
GetFilePosition()108     unsigned long GetFilePosition() const { return m_uFilePosition; }
GetRowIndex()109     unsigned int GetRowIndex() const { return m_uRowIndex; }
GetRowCount()110     size_t GetRowCount() { return m_pvRows->size(); }
GetRows()111     std::vector<CTemplate*>* GetRows() { return m_pvRows; }
GetNextRow()112     CTemplate* GetNextRow() { return GetRow(IncRowIndex()); }
GetCurRow()113     CTemplate* GetCurRow() { return GetRow(m_uRowIndex); }
114 
115     CTemplate* GetRow(unsigned int uIndex);
116     CString GetValue(const CString& sName, bool bFromIf = false);
117     // !Getters
118   private:
119     bool m_bReverse;           //!< Iterate through this loop in reverse order
120     bool m_bHasData;           //!< Tells whether this loop has real data or not
121     CString m_sName;           //!< The name portion of the <?LOOP name?> tag
122     unsigned int m_uRowIndex;  //!< The index of the current row we're on
123     unsigned long
124         m_uFilePosition;  //!< The file position of the opening <?LOOP?> tag
125     std::vector<CTemplate*>*
126         m_pvRows;  //!< This holds pointers to the templates associated with this loop
127 };
128 
129 class CTemplate : public MCString {
130   public:
CTemplate()131     CTemplate() : CTemplate("") {}
132 
CTemplate(const CString & sFileName)133     CTemplate(const CString& sFileName)
134         : MCString(),
135           m_pParent(nullptr),
136           m_sFileName(sFileName),
137           m_lsbPaths(),
138           m_mvLoops(),
139           m_vLoopContexts(),
140           m_spOptions(new CTemplateOptions),
141           m_vspTagHandlers() {}
142 
143     CTemplate(const std::shared_ptr<CTemplateOptions>& Options,
144               CTemplate* pParent = nullptr)
MCString()145         : MCString(),
146           m_pParent(pParent),
147           m_sFileName(""),
148           m_lsbPaths(),
149           m_mvLoops(),
150           m_vLoopContexts(),
151           m_spOptions(Options),
152           m_vspTagHandlers() {}
153 
154     virtual ~CTemplate();
155 
156     CTemplate(const CTemplate& other) = default;
157     CTemplate& operator=(const CTemplate& other) = default;
158 
159     //! Class for implementing custom tags in subclasses
AddTagHandler(std::shared_ptr<CTemplateTagHandler> spTagHandler)160     void AddTagHandler(std::shared_ptr<CTemplateTagHandler> spTagHandler) {
161         m_vspTagHandlers.push_back(spTagHandler);
162     }
163 
GetTagHandlers()164     std::vector<std::shared_ptr<CTemplateTagHandler>>& GetTagHandlers() {
165         if (m_pParent) {
166             return m_pParent->GetTagHandlers();
167         }
168 
169         return m_vspTagHandlers;
170     }
171 
172     CString ResolveLiteral(const CString& sString);
173 
174     void Init();
175 
176     CTemplate* GetParent(bool bRoot);
177     CString ExpandFile(const CString& sFilename, bool bFromInc = false);
178     bool SetFile(const CString& sFileName);
179 
180     void SetPath(const CString& sPath);  // Sets the dir:dir:dir type path to
181                                          // look at for templates, as of right
182                                          // now no ../../.. protection
183     CString MakePath(const CString& sPath) const;
184     void PrependPath(const CString& sPath, bool bIncludesOnly = false);
185     void AppendPath(const CString& sPath, bool bIncludesOnly = false);
186     void RemovePath(const CString& sPath);
187     void ClearPaths();
188     bool PrintString(CString& sRet);
189     bool Print(std::ostream& oOut);
190     bool Print(const CString& sFileName, std::ostream& oOut);
191     bool ValidIf(const CString& sArgs);
192     bool ValidExpr(const CString& sExpr);
193     bool IsTrue(const CString& sName);
194     bool HasLoop(const CString& sName);
195     CString GetValue(const CString& sName, bool bFromIf = false);
196     CTemplate& AddRow(const CString& sName);
197     CTemplate* GetRow(const CString& sName, unsigned int uIndex);
198     std::vector<CTemplate*>* GetLoop(const CString& sName);
199     void DelCurLoopContext();
200     CTemplateLoopContext* GetCurLoopContext();
201     CTemplate* GetCurTemplate();
202 
203     // Getters
GetFileName()204     const CString& GetFileName() const { return m_sFileName; }
205     // !Getters
206   private:
207     CTemplate* m_pParent;
208     CString m_sFileName;
209     std::list<std::pair<CString, bool>> m_lsbPaths;
210     std::map<CString, std::vector<CTemplate*>> m_mvLoops;
211     std::vector<CTemplateLoopContext*> m_vLoopContexts;
212     std::shared_ptr<CTemplateOptions> m_spOptions;
213     std::vector<std::shared_ptr<CTemplateTagHandler>> m_vspTagHandlers;
214 };
215 
216 #endif  // !ZNC_TEMPLATE_H
217