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 #include <znc/znc.h>
18 
19 using std::stringstream;
20 
21 class CNotesMod : public CModule {
22     bool m_bShowNotesOnLogin{};
23 
ListCommand(const CString & sLine)24     void ListCommand(const CString& sLine) { ListNotes(); }
25 
AddNoteCommand(const CString & sLine)26     void AddNoteCommand(const CString& sLine) {
27         CString sKey(sLine.Token(1));
28         CString sValue(sLine.Token(2, true));
29 
30         if (!GetNV(sKey).empty()) {
31             PutModule(
32                 t_s("That note already exists.  Use MOD <key> <note> to "
33                     "overwrite."));
34         } else if (AddNote(sKey, sValue)) {
35             PutModule(t_f("Added note {1}")(sKey));
36         } else {
37             PutModule(t_f("Unable to add note {1}")(sKey));
38         }
39     }
40 
ModCommand(const CString & sLine)41     void ModCommand(const CString& sLine) {
42         CString sKey(sLine.Token(1));
43         CString sValue(sLine.Token(2, true));
44 
45         if (AddNote(sKey, sValue)) {
46             PutModule(t_f("Set note for {1}")(sKey));
47         } else {
48             PutModule(t_f("Unable to add note {1}")(sKey));
49         }
50     }
51 
GetCommand(const CString & sLine)52     void GetCommand(const CString& sLine) {
53         CString sNote = GetNV(sLine.Token(1, true));
54 
55         if (sNote.empty()) {
56             PutModule(t_s("This note doesn't exist."));
57         } else {
58             PutModule(sNote);
59         }
60     }
61 
DelCommand(const CString & sLine)62     void DelCommand(const CString& sLine) {
63         CString sKey(sLine.Token(1));
64 
65         if (DelNote(sKey)) {
66             PutModule(t_f("Deleted note {1}")(sKey));
67         } else {
68             PutModule(t_f("Unable to delete note {1}")(sKey));
69         }
70     }
71 
72   public:
MODCONSTRUCTOR(CNotesMod)73     MODCONSTRUCTOR(CNotesMod) {
74         AddHelpCommand();
75         AddCommand("List", "", t_d("List notes"),
76                    [=](const CString& sLine) { ListCommand(sLine); });
77         AddCommand("Add", t_d("<key> <note>"), t_d("Add a note"),
78                    [=](const CString& sLine) { AddNoteCommand(sLine); });
79         AddCommand("Del", t_d("<key>"), t_d("Delete a note"),
80                    [=](const CString& sLine) { DelCommand(sLine); });
81         AddCommand("Mod", t_d("<key> <note>"), t_d("Modify a note"),
82                    [=](const CString& sLine) { ModCommand(sLine); });
83         AddCommand("Get", t_d("<key>"), "",
84                    [=](const CString& sLine) { GetCommand(sLine); });
85     }
86 
~CNotesMod()87     ~CNotesMod() override {}
88 
OnLoad(const CString & sArgs,CString & sMessage)89     bool OnLoad(const CString& sArgs, CString& sMessage) override {
90         m_bShowNotesOnLogin = !sArgs.Equals("-disableNotesOnLogin");
91         return true;
92     }
93 
GetWebMenuTitle()94     CString GetWebMenuTitle() override { return t_s("Notes"); }
95 
OnClientLogin()96     void OnClientLogin() override {
97         if (m_bShowNotesOnLogin) {
98             ListNotes(true);
99         }
100     }
101 
OnUserRaw(CString & sLine)102     EModRet OnUserRaw(CString& sLine) override {
103         if (sLine.Left(1) != "#") {
104             return CONTINUE;
105         }
106 
107         CString sKey;
108         bool bOverwrite = false;
109 
110         if (sLine == "#?") {
111             ListNotes(true);
112             return HALT;
113         } else if (sLine.Left(2) == "#-") {
114             sKey = sLine.Token(0).LeftChomp_n(2);
115             if (DelNote(sKey)) {
116                 PutModNotice(t_f("Deleted note {1}")(sKey));
117             } else {
118                 PutModNotice(t_f("Unable to delete note {1}")(sKey));
119             }
120             return HALT;
121         } else if (sLine.Left(2) == "#+") {
122             sKey = sLine.Token(0).LeftChomp_n(2);
123             bOverwrite = true;
124         } else if (sLine.Left(1) == "#") {
125             sKey = sLine.Token(0).LeftChomp_n(1);
126         }
127 
128         CString sValue(sLine.Token(1, true));
129 
130         if (!sKey.empty()) {
131             if (!bOverwrite && FindNV(sKey) != EndNV()) {
132                 PutModNotice(
133                     t_s("That note already exists.  Use /#+<key> <note> to "
134                         "overwrite."));
135             } else if (AddNote(sKey, sValue)) {
136                 if (!bOverwrite) {
137                     PutModNotice(t_f("Added note {1}")(sKey));
138                 } else {
139                     PutModNotice(t_f("Set note for {1}")(sKey));
140                 }
141             } else {
142                 PutModNotice(t_f("Unable to add note {1}")(sKey));
143             }
144         }
145 
146         return HALT;
147     }
148 
DelNote(const CString & sKey)149     bool DelNote(const CString& sKey) { return DelNV(sKey); }
150 
AddNote(const CString & sKey,const CString & sNote)151     bool AddNote(const CString& sKey, const CString& sNote) {
152         if (sKey.empty()) {
153             return false;
154         }
155 
156         return SetNV(sKey, sNote);
157     }
158 
ListNotes(bool bNotice=false)159     void ListNotes(bool bNotice = false) {
160         CClient* pClient = GetClient();
161 
162         if (pClient) {
163             CTable Table;
164             Table.AddColumn(t_s("Key"));
165             Table.AddColumn(t_s("Note"));
166             Table.SetStyle(CTable::ListStyle);
167 
168             for (MCString::iterator it = BeginNV(); it != EndNV(); ++it) {
169                 Table.AddRow();
170                 Table.SetCell(t_s("Key"), it->first);
171                 Table.SetCell(t_s("Note"), it->second);
172             }
173 
174             if (Table.size()) {
175                 unsigned int idx = 0;
176                 CString sLine;
177                 while (Table.GetLine(idx++, sLine)) {
178                     if (bNotice) {
179                         pClient->PutModNotice(GetModName(), sLine);
180                     } else {
181                         pClient->PutModule(GetModName(), sLine);
182                     }
183                 }
184             } else {
185                 if (bNotice) {
186                     PutModNotice(t_s("You have no entries."));
187                 } else {
188                     PutModule(t_s("You have no entries."));
189                 }
190             }
191         }
192     }
193 
OnWebRequest(CWebSock & WebSock,const CString & sPageName,CTemplate & Tmpl)194     bool OnWebRequest(CWebSock& WebSock, const CString& sPageName,
195                       CTemplate& Tmpl) override {
196         if (sPageName == "index") {
197             for (MCString::iterator it = BeginNV(); it != EndNV(); ++it) {
198                 CTemplate& Row = Tmpl.AddRow("NotesLoop");
199 
200                 Row["Key"] = it->first;
201                 Row["Note"] = it->second;
202             }
203 
204             return true;
205         } else if (sPageName == "delnote") {
206             DelNote(WebSock.GetParam("key", false));
207             WebSock.Redirect(GetWebPath());
208             return true;
209         } else if (sPageName == "addnote") {
210             AddNote(WebSock.GetParam("key"), WebSock.GetParam("note"));
211             WebSock.Redirect(GetWebPath());
212             return true;
213         }
214 
215         return false;
216     }
217 };
218 
219 template <>
TModInfo(CModInfo & Info)220 void TModInfo<CNotesMod>(CModInfo& Info) {
221     Info.SetWikiPage("notes");
222     Info.SetHasArgs(true);
223     Info.SetArgsHelpText(
224         Info.t_s("This user module takes up to one arguments. It can be "
225                  "-disableNotesOnLogin not to show notes upon client login"));
226 }
227 
228 USERMODULEDEFS(CNotesMod, t_s("Keep and replay notes"))
229