1 /*********************************************************************/
2 // dar - disk archive - a backup/restoration program
3 // Copyright (C) 2002-2052 Denis Corbin
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 //
19 // to contact the author : http://dar.linux.free.fr/email.html
20 /*********************************************************************/
21 
22     /// \file user_interaction.hpp
23     /// \brief defines the interaction between libdar and the user.
24     /// \ingroup API
25     ///
26     /// Three classes are defined
27     /// - user_interaction is the root class that you can use to make your own classes
28     /// - user_interaction_callback is a specialized inherited class which is implements
29     ///   user interaction thanks to callback functions
30     /// - user_interaction_blind provides fully usable objects that do not show anything
31     ///   and always assume a negative answer from the user
32     /// .
33 
34 ///////////////////////////////////////////////////////////////////////
35 // IMPORTANT : THIS FILE MUST ALWAYS BE INCLUDE AFTER infinint.hpp   //
36 //             (and infinint.hpp must be included too, always)       //
37 ///////////////////////////////////////////////////////////////////////
38 #include "infinint.hpp"
39 ///////////////////////////////////////////////////////////////////////
40 
41 
42 
43 #ifndef USER_INTERACTION_HPP
44 #define USER_INTERACTION_HPP
45 
46 #include "../my_config.h"
47 
48 #include <string>
49 #include "erreurs.hpp"
50 #include "integers.hpp"
51 #include "secu_string.hpp"
52 #include "on_pool.hpp"
53 
54 namespace libdar
55 {
56 
57 	/// \addtogroup API
58 	/// @{
59 
60 
61 
62 	/// This is a pure virtual class that is used by libdar when interaction with the user is required.
63 
64 	//! You can base your own class on it using C++ inheritance
65 	//! or use the class user_interaction_callback which implements
66 	//! the interaction based on callback functions.
67 	//! The user_interaction class is used by libdar in the following circumpstances:
68 	//! - when is required a boolean answer to a question the pause() method is used
69 	//! - when a warning needs to be displayed to the user the warning() method is used
70 	//! - when a directory listing needs to be returned to the user the listing() method is used
71 	//! .
72 	//! the printf() method is built over the warning() methods to display a formated message
73 	//! it has not to be redefined in any inherited class.
74 	//! If you want to define you own class as inherited class of user_interaction
75 	//! you need to overwrite:
76 	//! - the clone() method. It is used to make local temporary copies of objets
77 	//!  in libdar. It acts like the constructor copy but is virtual.
78 	//! - the pause() method
79 	//! - the warning() method
80 	//! - the listing() method (this is not mandatory).  inherited classes *can*
81 	//! overwrite the listing() method, which will be used if the use_listing
82 	//! is set to true thanks to the set_use_listing() protected method.
83 	//! In that case the listing of archive contents is done thanks to this listing()
84 	//! method instead of the warning() method.
85 	//! - get_string() method
86 	//! - get_secu_string() method
87 	//! .
88 	//! WARNING !
89 	//! if your own class has specific fields, you will probably
90 	//! need to redefine the copy constructor as well as operator =
91 	//! if you don't understand this and why, don't play trying making your
92 	//! own class, and/or read good C++ book about canonical form
93 	//! of a C++ class, as well as how to properly make an inherited class.
94 	//! And don't, complain if libdar segfault or core dumps. Libdar
95 	//! *needs* to make local copies of these objects, if the copy constructor
96 	//!  is not properly defined in your inherited class this will crash the application.
97 	//! \ingroup API
98     class user_interaction : public on_pool
99     {
100     public:
101 
102 	    /// class constructor.
103 	user_interaction();
~user_interaction()104 	virtual ~user_interaction() {};
105 
106 	    /// method used to ask a boolean question to the user.
107 
108 	    //! \param[in] message is the message to be displayed, that is the question.
109 	    //! \exception Euser_abort If the user answer "false" or "no" to the question the method
110 	    //! must throw an exception of type "Euser_abort".
pause(const std::string & message)111 	virtual void pause(const std::string & message)
112 	{
113 	    if(!pause2(message))
114 		throw Euser_abort(message);
115 	};
116 
117 	    /// alternative method to the pause() method
118 
119 	    //! \param[in] message The boolean question to ask to the user
120 	    //! \return the answer of the user (true/yes or no/false)
121 	    //! \note either pause2() or pause() *must* be overwritten, but not both.
122 	    //! libdar always calls pause() which default implementation relies on pause2() where it converts negative
123 	    //! return from pause2() by throwing the appropriated exception. As soon as you overwrite pause(),
124 	    //! pause2() is no more used.
pause2(const std::string & message)125 	virtual bool pause2(const std::string & message)
126 	{ throw Elibcall("user_interaction::pause2", "user_interaction::pause() or pause2() must be overwritten !"); };
127 
128 
129 	    /// \brief method used to display a warning or a message to the user.
130 	    ///
131 	    /// \param[in] message is the message to display.
132 	    /// \note since API 3.1.x this method must no more be ovewritten, instead
133 	    /// the protected method inherited_warning() must be used.
134 	void warning(const std::string & message);
135 
136 	    /// method used to ask a question that needs an arbitrary answer.
137 
138 	    //! \param[in] message is the question to display to the user.
139 	    //! \param[in] echo is set to false is the answer must not be shown while the user answers.
140 	    //! \return the user's answer.
141 	virtual std::string get_string(const std::string & message, bool echo) = 0;
142 
143 	    /// same a get_string() but uses secu_string instead
144 
145 	    //! \param[in] message is the question to display to the user.
146 	    //! \param[in] echo is set to false is the answer must not be shown while the user answers.
147 	    //! \return the user's answer.
148 	virtual secu_string get_secu_string(const std::string & message, bool echo) = 0;
149 
150 
151 	    /// optional method to use if you want file listing splitted in several fields.
152 	    /// If you need to use this feature, you have then to supply an implementation for this method,
153 	    /// in your inherited class which will be called by libdar in place of the warning method
154 	    /// You then also have to call the set_use_listing() method with true as parameter
155 	    /// from the constructor of your inherited class (for example) to tell libdar that the listing() method is
156 	    /// to be used in place of the warning() method for archive listing.
157 
158 	    //! \param[in] flag is the given information about the EA, compression, presence of saved data.
159 	    //! \param[in] perm is the access permission of the file.
160 	    //! \param[in] uid User ID of the file.
161 	    //! \param[in] gid Group ID of the file.
162 	    //! \param[in] size file size.
163 	    //! \param[in] date file modification date.
164 	    //! \param[in] filename file name.
165 	    //! \param[in] is_dir true if file is a directory.
166 	    //! \param[in] has_children true if file is a directory which is not empty.
167 	    //! \note This is not a pure virtual method, this is normal,
168 	    //! so your inherited class is not obliged to overwrite it.
169 	virtual void listing(const std::string & flag,
170 			     const std::string & perm,
171 			     const std::string & uid,
172 			     const std::string & gid,
173 			     const std::string & size,
174 			     const std::string & date,
175 			     const std::string & filename,
176 			     bool is_dir,
177 			     bool has_children);
178 
179 
180 
181 	    /// optional method to use if you want dar_manager database contents listing split in several fields.
182 	    /// if you want to use this feature, you have then to supply an implementation for this method
183 	    /// in your inherited class, method that will be called by libdar in place of the warning method.
184 	    /// You will also have to call the set_use_dar_manager_show_files() protected method with true as argument
185 	    /// from the constructor of your inherited class to tell libdar to use the dar_manager_show_files()
186 	    /// method in place of the warning() method.
187 
188 	    /// \param[in] filename name of the file
189 	    /// \param[in] data_change whether the backup owns the most recent data for the file
190 	    /// \param[in] ea_change whether the backup owns the most recent  Extended Attributes for the file
191 	    /// \note this method can be set for database::show_files() method to call it
192 	virtual void dar_manager_show_files(const std::string & filename,
193 					    bool data_change,
194 					    bool ea_change);
195 
196 
197 	    /// optional method to use if you want dar_manager database archive listing split in several fields
198 	    /// if you want to use this feature, you have then to supply an implementation for this method
199 	    /// in your inherited class, method that will be called by libdar in place of the warning method.
200 	    /// You will also have to call the set_use_dar_manager_contents() protected method with true as argument
201 	    /// from the constructor of your inherited class to tell libdar to use the dar_manager_contents()
202 	    /// method in place of the warning() method.
203 
204 	    /// \param[in] number is the number of the archive in the database
205 	    /// \param[in] chemin recorded path where to find this archive
206 	    /// \param[in] archive_name basename of this archive
207 	    /// \note this method can be set for database::show_contents() to call it
208 	virtual void dar_manager_contents(U_I number,
209 					  const std::string & chemin,
210 					  const std::string & archive_name);
211 
212 	    /// optional method to use if you want dar_manager statistics listing split in several fields
213 	    /// if you want to use this feature, you have then to supply an implementation for this method
214 	    /// in your inherited class, method that will be called by libdar in place of the warning method.
215 	    /// You will also have to call the set_use_dar_manager_statistics() protected method with true as argument
216 	    /// from the constructor of your inherited class to tell libdar to use the dar_manager_statistics()
217 	    /// method in place of the warning() method.
218 
219 	    /// \param[in] number archive number
220 	    /// \param[in] data_count amount of file which last version is located in this archive
221 	    /// \param[in] total_data total number of file covered in this database
222 	    /// \param[in] ea_count amount of EA which last version is located in this archive
223 	    /// \param[in] total_ea total number of file that have EA covered by this database
224 	    /// \note this method can be set for database::show_most_recent_stats() method to call it
225 	virtual void dar_manager_statistics(U_I number,
226 					    const infinint & data_count,
227 					    const infinint & total_data,
228 					    const infinint & ea_count,
229 					    const infinint & total_ea);
230 
231 	    /// optional method to use if you want dar_manager statistics listing split in several fields
232 	    /// if you want to use this feature, you have then to supply an implementation for this method
233 	    /// in your inherited class, method that will be called by libdar in place of the warning method.
234 	    /// You will also have to call the set_use_dar_manager_show_version() protected method with true as argument
235 	    /// from the constructor of your inherited class to tell libdar to use the dar_manager_show_version()
236 	    /// method in place of the warning() method.
237 
238 	    /// \param[in] number archive number
239 	    /// \param[in] data_date is the last modification date of the requested file in thie archive whose number is "number"
240 	    /// \param[in] data_presence is the nature of this modification, true if the data was saved, false if it was deleted
241 	    /// \param[in] ea_date is the date of the EA for the requested file in the archive whose number is "number"
242 	    /// \param[in] ea_presence is the nature of this modification, true if the EAs were saved, false if they were deleted
243 	    /// \note this method can be set for database::show_version() method to call it
244 	virtual void dar_manager_show_version(U_I number,
245 					      const std::string & data_date,
246 					      const std::string & data_presence,
247 					      const std::string & ea_date,
248 					      const std::string & ea_presence);
249 
250 	    /// libdar uses this call to format output before send to warning() method.
251 
252 	    //! This is not a virtual method, it has not to be overwritten, it is
253 	    //! just a sublayer over warning()
254 	    //! Supported masks for the format string are:
255 	    //! - \%s \%c \%d \%\%  (normal behavior)
256 	    //! - \%i (matches infinint *)
257 	    //! - \%S (matches std::string *)
258 	    //! .
259 	void printf(const char *format, ...);
260 
261 	    /// for libdar to know if it is interesting to use listing(), dar_manager_show_files(),
262 	    /// dar_manager_contents(), dar_manager_statistics() or to keep reporting listing thanks
263 	    /// to the warning() method,
264 
265 	    //! this is not a virtual method, it has not to be overwritten in inherited classes.
get_use_listing() const266 	bool get_use_listing() const { return use_listing; };
267 	    //! this is not a virtual method, it has not to be overwritten in inherited classes.
get_use_dar_manager_show_files() const268 	bool get_use_dar_manager_show_files() const { return use_dar_manager_show_files; };
269 	    //! this is not a virtual method, it has not to be overwritten in inherited classes.
get_use_dar_manager_contents() const270 	bool get_use_dar_manager_contents() const { return use_dar_manager_contents; };
271 	    //! this is not a virtual method, it has not to be overwritten in inherited classes.
get_use_dar_manager_statistics() const272 	bool get_use_dar_manager_statistics() const { return use_dar_manager_statistics; };
273 	    //! this is not a virtual method, it has not to be overwritten in inherited classes.
get_use_dar_manager_show_version() const274 	bool get_use_dar_manager_show_version() const { return use_dar_manager_show_version; };
275 
276 
277 	    /// make a newly allocated object which has the same properties as "this".
278 
279 	    //! This *is* a virtual method, it *must* be overwritten in any inherited class
280 	    //! copy constructor and = operator may have to be overwritten too if necessary
281 	    //! Warning !
282 	    //! clone() must throw exception if necessary (Ememory), but never
283 	    //! return a nullptr pointer !
284 	virtual user_interaction *clone() const = 0;
285 
286 	    /// make a pause each N line of output when calling the warning method
287 
288 	    //! \param[in] num is the number of line to display at once, zero for unlimited display
289 	    //! \note. Since API 3.1, the warning method is no more a pure virtual function
290 	    //! you need to call the parent warning method in your method for this warning_with_more
291 	    //! method works as expected.
warning_with_more(U_I num)292 	void warning_with_more(U_I num) { at_once = num; count = 0; };
293 
294     protected:
295 
296 	    /// method to be called with true as argument if you have defined a listing() method.
297 
298 	    //! in the constructor of any inherited class that define a listing() method
299 	    //! it is advisable to call set_use_listing() with true as argument for libdar
300 	    //! knows that the listing() call has to be used in place of the warning() call
301 	    //! for file listing.
set_use_listing(bool val)302 	void set_use_listing(bool val) { use_listing = val; };
303 
304 	    /// method to be called with true as argument if you have defined a dar_manager_show_files() method.
set_use_dar_manager_show_files(bool val)305 	void set_use_dar_manager_show_files(bool val) { use_dar_manager_show_files = val; };
306 
307 	    /// method to be called with true as argument if you have defined a dar_manager_contents() method.
set_use_dar_manager_contents(bool val)308 	void set_use_dar_manager_contents(bool val) { use_dar_manager_contents = val; };
309 
310 	    /// method to be called with true as argument if you have defined a dar_manager_statistics() method.
set_use_dar_manager_statistics(bool val)311 	void set_use_dar_manager_statistics(bool val) { use_dar_manager_statistics = val; };
312 
313 	    /// method to be called with true as argument if you have defined a dar_manager_show_version() method.
set_use_dar_manager_show_version(bool val)314 	void set_use_dar_manager_show_version(bool val) { use_dar_manager_show_version = val; };
315 
316 	    /// need to be overwritten in place of the warning() method since API 3.1.x
317 
318 	    /// \param[in] message message to display
319 	    ///
320 	virtual void inherited_warning(const std::string & message) = 0;
321 
322     private:
323 	bool use_listing;
324 	bool use_dar_manager_show_files;
325 	bool use_dar_manager_contents;
326 	bool use_dar_manager_statistics;
327 	bool use_dar_manager_show_version;
328 	U_I at_once, count;
329 
330     };
331 
332 
333 	/// full implemented class for user_interaction based on callback functions.
334 
335 	//! this class is an inherited class of user_interaction it is used by
336 	//! dar command line programs, but you can use it if you wish.
337 	//! \ingroup API
338     class user_interaction_callback : public user_interaction
339     {
340     public:
341 
342 	    /// constructor which receive the callback functions.
343 
344 	    //! \param[in] x_warning_callback is used by warning() method
345 	    //! \param[in] x_answer_callback is used by the pause() method
346 	    //! \param[in] x_string_callback is used by get_string() method
347 	    //! \param[in] x_secu_string_callback is used by get_secu_string() method
348 	    //! \param[in] context_value will be passed as last argument of callbacks when
349 	    //! called from this object.
350 	    //! \note The context argument of each callback is set with the context_value given
351 	    //! in the user_interaction_callback object constructor. The value can
352 	    //! can be any arbitrary value (nullptr is valid), and can be used as you wish.
353 	    //! Note that the listing callback is not defined here, but thanks to a specific method
354 	user_interaction_callback(void (*x_warning_callback)(const std::string &x, void *context),
355 				  bool (*x_answer_callback)(const std::string &x, void *context),
356 				  std::string (*x_string_callback)(const std::string &x, bool echo, void *context),
357 				  secu_string (*x_secu_string_callback)(const std::string &x, bool echo, void *context),
358 				  void *context_value);
359 
360 	    /// overwritting method from parent class.
361        	void pause(const std::string & message);
362 	    /// overwritting method from parent class.
363 	std::string get_string(const std::string & message, bool echo);
364 	    /// overwritting method from parent class.
365 	secu_string get_secu_string(const std::string & message, bool echo);
366 	    /// overwritting method from parent class.
367         void listing(const std::string & flag,
368 		     const std::string & perm,
369 		     const std::string & uid,
370 		     const std::string & gid,
371 		     const std::string & size,
372 		     const std::string & date,
373 		     const std::string & filename,
374 		     bool is_dir,
375 		     bool has_children);
376 
377 	    /// overwritting method from parent class
378 	void dar_manager_show_files(const std::string & filename,
379 				    bool available_data,
380 				    bool available_ea);
381 
382 	    /// overwritting method from parent class
383 	void dar_manager_contents(U_I number,
384 				  const std::string & chemin,
385 				  const std::string & archive_name);
386 
387 	    /// overwritting method from parent class
388 	void dar_manager_statistics(U_I number,
389 				    const infinint & data_count,
390 				    const infinint & total_data,
391 				    const infinint & ea_count,
392 				    const infinint & total_ea);
393 
394 	    /// overwritting method from parent class
395 	void dar_manager_show_version(U_I number,
396 				      const std::string & data_date,
397 				      const std::string & data_presence,
398 				      const std::string & ea_date,
399 				      const std::string & ea_presence);
400 
401 	    /// You can set a listing callback thanks to this method.
402 
403 	    //! If set, when file listing will this callback function will
404 	    //! be used instead of the x_warning_callback given as argument
405 	    //! of the constructor.
set_listing_callback(void (* callback)(const std::string & flag,const std::string & perm,const std::string & uid,const std::string & gid,const std::string & size,const std::string & date,const std::string & filename,bool is_dir,bool has_children,void * context))406         void set_listing_callback(void (*callback)(const std::string & flag,
407 						   const std::string & perm,
408 						   const std::string & uid,
409 						   const std::string & gid,
410 						   const std::string & size,
411 						   const std::string & date,
412 						   const std::string & filename,
413 						   bool is_dir,
414 						   bool has_children,
415 						   void *context))
416 	{
417 	    tar_listing_callback = callback;
418 	    set_use_listing(true); // this is to inform libdar to use listing()
419 	};
420 
421 	    // You can set a dar_manager_show_files callback thanks to this method
422 
set_dar_manager_show_files_callback(void (* callback)(const std::string & filename,bool available_data,bool available_ea,void * context))423 	void set_dar_manager_show_files_callback(void (*callback)(const std::string & filename,
424 								  bool available_data,
425 								  bool available_ea,
426 								  void *context))
427 	{
428 	    dar_manager_show_files_callback = callback;
429 	    set_use_dar_manager_show_files(true); // this is to inform libdar to use the dar_manager_show_files() method
430 	};
431 
set_dar_manager_contents_callback(void (* callback)(U_I number,const std::string & chemin,const std::string & archive_name,void * context))432 	void set_dar_manager_contents_callback(void (*callback)(U_I number,
433 								const std::string & chemin,
434 								const std::string & archive_name,
435 								void *context))
436 	{
437 	    dar_manager_contents_callback = callback;
438 	    set_use_dar_manager_contents(true); // this is to inform libdar to use the dar_manager_contents() method
439 	};
440 
set_dar_manager_statistics_callback(void (* callback)(U_I number,const infinint & data_count,const infinint & total_data,const infinint & ea_count,const infinint & total_ea,void * context))441 	void set_dar_manager_statistics_callback(void (*callback)(U_I number,
442 								  const infinint & data_count,
443 								  const infinint & total_data,
444 								  const infinint & ea_count,
445 								  const infinint & total_ea,
446 								  void *context))
447 	{
448 	    dar_manager_statistics_callback = callback;
449 	    set_use_dar_manager_statistics(true); // this is to inform libdar to use the dar_manager_statistics() method
450 	};
451 
set_dar_manager_show_version_callback(void (* callback)(U_I number,const std::string & data_date,const std::string & data_presence,const std::string & ea_date,const std::string & ea_presence,void * context))452 	void set_dar_manager_show_version_callback(void (*callback)(U_I number,
453 								    const std::string & data_date,
454 								    const std::string & data_presence,
455 								    const std::string & ea_date,
456 								    const std::string & ea_presence,
457 								    void *context))
458 	{
459 	    dar_manager_show_version_callback = callback;
460 	    set_use_dar_manager_show_version(true);  // this is to inform libdar to use the dar_manager_show_version() method
461 	};
462 
463 
464 	    /// overwritting method from parent class.
465 	virtual user_interaction *clone() const;
466 
467     protected:
468 	    /// change the context value of the object that will be given to callback functions
change_context_value(void * new_value)469 	void change_context_value(void *new_value) { context_val = new_value; };
470 
471 	    /// overwritting method from parent class.
472 	void inherited_warning(const std::string & message);
473 
474     private:
475 	void (*warning_callback)(const std::string & x, void *context);  // pointer to function
476 	bool (*answer_callback)(const std::string & x, void *context);   // pointer to function
477 	std::string (*string_callback)(const std::string & x, bool echo, void *context); // pointer to function
478 	secu_string (*secu_string_callback)(const std::string & x, bool echo, void *context); // pointer to function
479 	void (*tar_listing_callback)(const std::string & flags,
480 				     const std::string & perm,
481 				     const std::string & uid,
482 				     const std::string & gid,
483 				     const std::string & size,
484 				     const std::string & date,
485 				     const std::string & filename,
486 				     bool is_dir,
487 				     bool has_children,
488 				     void *context);
489 	void (*dar_manager_show_files_callback)(const std::string & filename,
490 						bool available_data,
491 						bool available_ea,
492 						void *context);
493 	void (*dar_manager_contents_callback)(U_I number,
494 					      const std::string & chemin,
495 					      const std::string & archive_name,
496 					      void *context);
497 	void (*dar_manager_statistics_callback)(U_I number,
498 						const infinint & data_count,
499 						const infinint & total_data,
500 						const infinint & ea_count,
501 						const infinint & total_ea,
502 						void *context);
503 	void (*dar_manager_show_version_callback)(U_I number,
504 						  const std::string & data_date,
505 						  const std::string & data_presence,
506 						  const std::string & ea_date,
507 						  const std::string & ea_presence,
508 						  void *context);
509 
510 	void *context_val;
511     };
512 
513 
514 	/// full implementation class for user_interaction, which shows nothing and assumes answer "no" to any question
515 
516     class user_interaction_blind : public user_interaction
517     {
518     public:
pause2(const std::string & message)519 	bool pause2(const std::string & message) { return false; };
520 
get_string(const std::string & message,bool echo)521 	std::string get_string(const std::string & message, bool echo) { return "user_interaction_blind, is blindly answering no"; };
get_secu_string(const std::string & message,bool echo)522 	secu_string get_secu_string(const std::string & message, bool echo) { return secu_string(); };
523 
clone() const524 	user_interaction *clone() const { user_interaction *ret = new (get_pool()) user_interaction_blind(); if(ret == nullptr) throw Ememory("user_interaction_blind::clone"); return ret; };
525 
526     protected:
inherited_warning(const std::string & message)527 	void inherited_warning(const std::string & message) {}; // do not display any warning, this is "bind user_interaction" !
528 
529     };
530 
531 	/// @}
532 
533 } // end of namespace
534 
535 #endif
536