1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2016-2016 Planets Communications B.V.
5    Copyright (C) 2015-2020 Bareos GmbH & Co. KG
6 
7    This program is Free Software; you can redistribute it and/or
8    modify it under the terms of version three of the GNU Affero General Public
9    License as published by the Free Software Foundation and included
10    in the file LICENSE.
11 
12    This program is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15    Affero General Public License for more details.
16 
17    You should have received a copy of the GNU Affero General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20    02110-1301, USA.
21 */
22 /*
23  * Joerg Steffens, April 2015
24  */
25 /**
26  * @file
27  * Output Formatter prototypes
28  */
29 
30 #ifndef BAREOS_LIB_OUTPUT_FORMATTER_H_
31 #define BAREOS_LIB_OUTPUT_FORMATTER_H_
32 
33 #define MSG_TYPE_INFO "info"
34 #define MSG_TYPE_WARNING "warning"
35 #define MSG_TYPE_ERROR "error"
36 
37 #define OF_MAX_NR_HIDDEN_COLUMNS 64
38 
39 #if HAVE_JANSSON
40 /**
41  * See if the source file needs the full JANSSON namespace or that we can
42  * get away with using a forward declaration of the json_t struct.
43  */
44 #  ifndef NEED_JANSSON_NAMESPACE
45 typedef struct json_t json_t;
46 #  else
47 #    include <jansson.h>
48 #  endif
49 
50 #  define UA_JSON_FLAGS_NORMAL JSON_INDENT(2)
51 #  define UA_JSON_FLAGS_COMPACT JSON_COMPACT
52 
53 #endif /* HAVE_JANSSON */
54 
55 #include "lib/alist.h"
56 #include "lib/api_mode.h"
57 
58 class PoolMem;
59 
60 /**
61  * Filtering states.
62  */
63 typedef enum of_filter_state
64 {
65   OF_FILTER_STATE_SHOW,
66   OF_FILTER_STATE_SUPPRESS,
67   OF_FILTER_STATE_UNKNOWN
68 } of_filter_state;
69 
70 /**
71  * Filtering types.
72  */
73 typedef enum of_filter_type
74 {
75   OF_FILTER_LIMIT,
76   OF_FILTER_OFFSET,
77   OF_FILTER_ACL,
78   OF_FILTER_RESOURCE,
79   OF_FILTER_ENABLED,
80   OF_FILTER_DISABLED
81 } of_filter_type;
82 
83 typedef struct of_limit_filter_tuple {
84   int limit = 0; /* Filter output to a maximum of limit entries */
85 } of_limit_filter_tuple;
86 
87 typedef struct of_offset_filter_tuple {
88   int offset = 0;
89 } of_offset_filter_tuple;
90 
91 typedef struct of_acl_filter_tuple {
92   int column = 0;  /* Filter resource is located in this column */
93   int acltype = 0; /* Filter resource based on this ACL type */
94 } of_acl_filter_tuple;
95 
96 typedef struct of_res_filter_tuple {
97   int column = 0;  /* Filter resource is located in this column */
98   int restype = 0; /* Filter resource based on this resource type */
99 } of_res_filter_tuple;
100 
101 typedef struct of_filter_tuple {
102   of_filter_type type;
103   union {
104     of_limit_filter_tuple limit_filter;
105     of_offset_filter_tuple offset_filter;
106     of_acl_filter_tuple acl_filter;
107     of_res_filter_tuple res_filter;
108   } u;
109 } of_filter_tuple;
110 
111 /**
112  * Actual output formatter class.
113  */
114 class OutputFormatter {
115  public:
116   /*
117    * Typedefs.
118    */
119   typedef bool(SEND_HANDLER)(void* ctx, const char* fmt, ...);
120 
121   typedef of_filter_state(FILTER_HANDLER)(void* ctx,
122                                           void* data,
123                                           of_filter_tuple* tuple);
124 
125  private:
126   /*
127    * Members
128    */
129   int api = 0;
130   bool compact = false;
131   SEND_HANDLER* send_func = nullptr;
132   FILTER_HANDLER* filter_func = nullptr;
133   void* send_ctx = nullptr;
134   void* filter_ctx = nullptr;
135   alist* filters = nullptr;
136   char* hidden_columns = nullptr;
137   PoolMem* result_message_plain = nullptr;
138   static const unsigned int max_message_length_shown_in_error = 1024;
139   int num_rows_filtered = 0;
140 #if HAVE_JANSSON
141   json_t* result_json = nullptr;
142   alist* result_stack_json = nullptr;
143   json_t* message_object_json = nullptr;
144 #endif
145 
146  private:
147   /*
148    * Methods
149    */
get_num_rows_filtered()150   int get_num_rows_filtered() { return num_rows_filtered; }
SetNumRowsFiltered(int value)151   void SetNumRowsFiltered(int value) { num_rows_filtered = value; }
ClearNumRowsFiltered()152   void ClearNumRowsFiltered() { SetNumRowsFiltered(0); }
153 
154   void CreateNewResFilter(of_filter_type type, int column, int restype);
155   bool ProcessTextBuffer();
156 
157   /*
158    * reformat string.
159    * remove newlines and replace tabs with a single space.
160    * wrap < 0: no modification
161    * wrap = 0: reformat to single line
162    * wrap > 0: if api==0: wrap after x characters, else no modifications
163    */
164   void rewrap(PoolMem& string, int wrap);
165 
166 #if HAVE_JANSSON
167   bool JsonSendErrorMessage(const char* message);
168 #endif
169 
170  public:
171   /*
172    * Methods
173    */
174   OutputFormatter(SEND_HANDLER* send_func,
175                   void* send_ctx,
176                   FILTER_HANDLER* filter_func,
177                   void* filter_ctx,
178                   int api_mode = API_MODE_OFF);
179 
180   ~OutputFormatter();
181 
SetMode(int mode)182   void SetMode(int mode) { api = mode; }
GetMode()183   int GetMode() { return api; }
184 
185   /*
186    * Allow to set compact output mode. Only used for json api mode.
187    * There it can reduce the size of message by 1/3.
188    */
SetCompact(bool value)189   void SetCompact(bool value) { compact = value; }
GetCompact()190   bool GetCompact() { return compact; }
191 
192   void Decoration(const char* fmt, ...);
193 
194   void ArrayStart(const char* name, const char* fmt = NULL);
195   void ArrayEnd(const char* name, const char* fmt = NULL);
196 
197   void ArrayItem(bool value, const char* value_fmt = NULL);
198   void ArrayItem(uint64_t value, const char* value_fmt = NULL);
199   void ArrayItem(const char* value,
200                  const char* value_fmt = NULL,
201                  bool format = true);
202 
203   void ObjectStart(const char* name = NULL,
204                    const char* fmt = NULL,
205                    bool case_sensitiv_name = false);
206   void ObjectEnd(const char* name = NULL, const char* fmt = NULL);
207 
208   /*
209    * boolean and integer can not be used to distinguish overloading functions,
210    * therefore the bool function have the postfix _bool.
211    * The boolean value is given a string ("true" or "false") to the value_fmt
212    * string. The format string must therefore match "%s".
213    */
214   void ObjectKeyValueBool(const char* key, bool value);
215   void ObjectKeyValueBool(const char* key, bool value, const char* value_fmt);
216   void ObjectKeyValueBool(const char* key,
217                           const char* key_fmt,
218                           bool value,
219                           const char* value_fmt);
220   void ObjectKeyValue(const char* key, uint64_t value);
221   void ObjectKeyValue(const char* key, uint64_t value, const char* value_fmt);
222   void ObjectKeyValue(const char* key,
223                       const char* key_fmt,
224                       uint64_t value,
225                       const char* value_fmt);
226   void ObjectKeyValueSignedInt(const char* key, int64_t value);
227   void ObjectKeyValueSignedInt(const char* key,
228                                int64_t value,
229                                const char* value_fmt);
230   void ObjectKeyValueSignedInt(const char* key,
231                                const char* key_fmt,
232                                int64_t value,
233                                const char* value_fmt);
234   void ObjectKeyValue(const char* key, const char* value, int wrap = -1);
235   void ObjectKeyValue(const char* key,
236                       const char* value,
237                       const char* value_fmt,
238                       int wrap = -1);
239   void ObjectKeyValue(const char* key,
240                       const char* key_fmt,
241                       const char* value,
242                       const char* value_fmt,
243                       int wrap = -1);
244 
245   /*
246    * some programs (BAT in api mode 1) parses data message by message,
247    * instead of using a separator.
248    * An example for this is BAT with the ".defaults job" command in API mode 1.
249    * In this cases, the SendBuffer function must be called at between two
250    * messages. In API mode 2 this function has no effect. This function should
251    * only be used, when there is a specific need for it.
252    */
253   void SendBuffer();
254 
255   /*
256    * Filtering.
257    */
258   void AddLimitFilterTuple(int limit);
259   void AddOffsetFilterTuple(int offset);
260   void AddAclFilterTuple(int column, int acltype);
261   void AddResFilterTuple(int column, int restype);
262   void AddEnabledFilterTuple(int column, int restype);
263   void AddDisabledFilterTuple(int column, int restype);
264   void ClearFilters();
HasFilters()265   bool HasFilters() { return filters && !filters->empty(); }
266   bool has_acl_filters();
267   bool FilterData(void* data);
268 
269   /*
270    * Hidden columns.
271    */
272   void AddHiddenColumn(int column);
273   bool IsHiddenColumn(int column);
274   void ClearHiddenColumns();
275 
276   void message(const char* type, PoolMem& message);
277 
278   void FinalizeResult(bool result);
279 
280 #if HAVE_JANSSON
281   bool JsonArrayItemAdd(json_t* value);
282   bool JsonKeyValueAddBool(const char* key, bool value);
283   bool JsonKeyValueAdd(const char* key, uint64_t value);
284   bool JsonKeyValueAdd(const char* key, const char* value);
285   void JsonAddMessage(const char* type, PoolMem& message);
286   bool JsonHasErrorMessage();
287   void JsonFinalizeResult(bool result);
288 #endif
289 };
290 
291 #ifdef HAVE_JANSSON
292 /*
293  * JSON output helper functions
294  */
295 struct s_kw;
296 struct ResourceItem;
297 
298 json_t* json_item(s_kw* item);
299 json_t* json_item(ResourceItem* item);
300 json_t* json_items(ResourceItem items[]);
301 #endif
302 
303 #endif
304