1 /*
2  *  Tvheadend - idnode (class) system
3  *
4  *  Copyright (C) 2013 Andreas Öman
5  *
6  *  This program is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more 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 #ifndef __TVH_IDNODE_H__
21 #define __TVH_IDNODE_H__
22 
23 #include "tvheadend.h"
24 #include "prop.h"
25 #include "uuid.h"
26 
27 #include <regex.h>
28 
29 struct access;
30 typedef struct idnode idnode_t;
31 typedef struct idnode_save idnode_save_t;
32 
33 #define IDNODE_SAVE_DELAY (3 * MONOCLOCK_RESOLUTION)
34 
35 #define SAVEPTR_OUTOFSERVICE ((void *)((intptr_t)-1LL))
36 
37 /*
38  * Node set
39  */
40 typedef struct idnode_set
41 {
42   idnode_t **is_array;  ///< Array of nodes
43   size_t     is_alloc;  ///< Size of is_array
44   size_t     is_count;  ///< Current usage of is_array
45   uint8_t    is_sorted; ///< Sorted array of nodes
46 } idnode_set_t;
47 
48 /*
49  * Property groups
50  */
51 typedef struct property_group
52 {
53   const char *name;
54   uint32_t    number;
55   uint32_t    parent;
56   uint32_t    column;
57 } property_group_t;
58 
59 /*
60  * Class definition
61  */
62 #define IDCLASS_ALWAYS_SAVE    (1<<0)      ///< Always call the save callback
63 
64 #define CLASS_DOC(name) extern const char *tvh_doc_##name##_class[];
65 
66 typedef struct idclass idclass_t;
67 struct idclass {
68   const struct idclass   *ic_super;        ///< Parent class
69   const char             *ic_class;        ///< Class name
70   const char             *ic_caption;      ///< Class description
71   const char             *ic_order;        ///< Property order (comma-separated)
72   const char            **ic_doc;          ///< NULL terminated array of strings
73   const property_group_t *ic_groups;       ///< Groups for visual representation
74   const property_t       *ic_properties;   ///< Property list
75   const char             *ic_event;        ///< Events to fire on add/delete/title
76   uint32_t                ic_perm_def;     ///< Default permissions
77   uint32_t                ic_flags;        ///< Extra flags
78   idnode_t               *ic_snode;        ///< Simple node
79 
80   /* Callbacks */
81   idnode_set_t   *(*ic_get_childs) (idnode_t *self);
82   const char     *(*ic_get_title)  (idnode_t *self, const char *lang);
83   void            (*ic_changed)    (idnode_t *self);
84   htsmsg_t       *(*ic_save)       (idnode_t *self, char *filename, size_t fsize);
85   void            (*ic_delete)     (idnode_t *self);
86   void            (*ic_moveup)     (idnode_t *self);
87   void            (*ic_movedown)   (idnode_t *self);
88   int             (*ic_perm)       (idnode_t *self, struct access *a, htsmsg_t *msg_to_write);
89 };
90 
91 
92 typedef RB_HEAD(, idnode) idnodes_rb_t;
93 
94 /*
95  * Node definition
96  */
97 struct idnode {
98   tvh_uuid_t        in_uuid;                ///< Unique ID
99   RB_ENTRY(idnode)  in_link;                ///< Global hash
100   RB_ENTRY(idnode)  in_domain_link;         ///< Root class link (domain)
101   idnodes_rb_t     *in_domain;              ///< Domain nodes
102   const idclass_t  *in_class;               ///< Class definition
103   struct access    *in_access;              ///< Actual permissions
104   idnode_save_t    *in_save;                ///< Pointer to the save link
105 };
106 
107 /*
108  * Node save list
109  */
110 struct idnode_save {
111   TAILQ_ENTRY(idnode_save)  ise_link;       ///< List chain
112   idnode_t                 *ise_node;       ///< Node owning this
113   int64_t                   ise_reqtime;    ///< First request
114 };
115 
116 /*
117  * Simple list
118  */
119 typedef struct idnode_slist {
120   const char       *id;
121   const char       *name;
122   size_t            off;
123 } idnode_slist_t;
124 
125 /*
126  * Node list mapping definition
127  */
128 struct idnode_list_mapping;
129 
130 typedef struct idnode_list_head {
131   struct idnode_list_mapping *lh_first;
132 } idnode_list_head_t;
133 
134 typedef struct idnode_list_mapping {
135   LIST_ENTRY(idnode_list_mapping) ilm_in1_link;
136   LIST_ENTRY(idnode_list_mapping) ilm_in2_link;
137 
138   idnode_t *ilm_in1;
139   idnode_t *ilm_in2;
140 
141   uint8_t ilm_in1_save;
142   uint8_t ilm_in2_save;
143   uint8_t ilm_mark;
144 } idnode_list_mapping_t;
145 
146 /*
147  * Sorting definition
148  */
149 typedef struct idnode_sort {
150   const char *lang; ///< Language (UI)
151   const char *key;  ///< Sort key
152   enum {
153     IS_ASC,
154     IS_DSC
155   }           dir;  ///< Sort direction
156 } idnode_sort_t;
157 
158 /*
159  * Filter definition
160  */
161 typedef struct idnode_filter_ele
162 {
163   LIST_ENTRY(idnode_filter_ele) link; ///< List link
164 
165   int checked;
166   char *key;                          ///< Filter key
167   enum {
168     IF_STR,
169     IF_NUM,
170     IF_DBL,
171     IF_BOOL
172   } type;                             ///< Filter type
173   union {
174     int      b;
175     char    *s;
176     struct {
177       int64_t n;
178       int64_t intsplit;
179     } n;
180     double   dbl;
181     regex_t  re;
182   } u;                                ///< Filter data
183   enum {
184     IC_EQ, ///< Equals
185     IC_LT, ///< LT
186     IC_GT, ///< GT
187     IC_IN, ///< contains (STR only)
188     IC_RE, ///< regexp (STR only)
189   } comp;                             ///< Filter comparison
190 } idnode_filter_ele_t;
191 
192 typedef LIST_HEAD(,idnode_filter_ele) idnode_filter_t;
193 
194 extern idnode_t tvhlog_conf;
195 extern const idclass_t tvhlog_conf_class;
196 
197 void idnode_boot(void);
198 void idnode_init(void);
199 void idnode_done(void);
200 
201 #define IDNODE_SHORT_UUID (1<<0)
202 
203 int  idnode_insert(idnode_t *in, const char *uuid, const idclass_t *idc, int flags);
204 void idnode_unlink(idnode_t *in);
205 
206 uint32_t      idnode_get_short_uuid (const idnode_t *in);
207 const char   *idnode_uuid_as_str  (const idnode_t *in, char *buf);
208 idnode_set_t *idnode_get_childs   (idnode_t *in);
209 const char   *idnode_get_title    (idnode_t *in, const char *lang);
210 int           idnode_is_leaf      (idnode_t *in);
211 int           idnode_is_instance  (idnode_t *in, const idclass_t *idc);
212 void          idnode_delete       (idnode_t *in);
213 void          idnode_moveup       (idnode_t *in);
214 void          idnode_movedown     (idnode_t *in);
215 
216 void          idnode_changed      (idnode_t *in);
217 
218 void         *idnode_find    (const char *uuid, const idclass_t *idc, const idnodes_rb_t *nodes);
219 idnode_set_t *idnode_find_all(const idclass_t *idc, const idnodes_rb_t *nodes);
220 
221 
222 void idnode_notify (idnode_t *in, const char *action);
223 void idnode_notify_changed (void *in);
224 void idnode_notify_title_changed (void *in, const char *lang);
225 
226 void idclass_register ( const idclass_t *idc );
227 const idclass_t *idclass_find ( const char *name );
228 idclass_t const **idclass_find_all(void);
229 idclass_t const **idclass_find_children(const char *name);
230 const char **idclass_get_doc(const idclass_t *idc);
231 const char *idclass_get_caption ( const idclass_t *idc, const char *lang );
232 htsmsg_t *idclass_serialize0 (const idclass_t *idc, htsmsg_t *list, int optmask, const char *lang);
233 htsmsg_t *idnode_serialize0  (idnode_t *self, htsmsg_t *list, int optmask, const char *lang);
234 void      idnode_read0  (idnode_t *self, htsmsg_t *m, htsmsg_t *list, int optmask, const char *lang);
235 int       idnode_write0 (idnode_t *self, htsmsg_t *m, int optmask, int dosave);
236 void      idnode_save_check (idnode_t *self, int weak);
237 
238 #define idclass_serialize(idc, lang)    idclass_serialize0(idc, NULL, 0, lang)
239 #define idclass_serializedoc(idc, lang) idclass_serialize0(idc, NULL, PO_DOC, lang)
240 #define idnode_serialize(in, lang)      idnode_serialize0(in, NULL, 0, lang)
241 #define idnode_load(in, m)     idnode_write0(in, m, PO_NOSAVE, 0)
242 #define idnode_save(in, m)     idnode_read0(in, m, NULL, PO_NOSAVE | PO_USERAW, NULL)
243 #define idnode_update(in, m)   idnode_write0(in, m, PO_RDONLY | PO_WRONCE, 1)
244 
245 int idnode_perm(idnode_t *self, struct access *a, htsmsg_t *msg_to_write);
idnode_perm_unset(idnode_t * self)246 static inline void idnode_perm_unset(idnode_t *self) { self->in_access = NULL; }
247 
248 #define idnode_lang(self) \
249   (((idnode_t *)self)->in_access ? \
250    ((idnode_t *)self)->in_access->aa_lang : NULL)
251 #define idnode_lang_ui(self) \
252   (((idnode_t *)self)->in_access ? \
253    ((idnode_t *)self)->in_access->aa_lang_ui : NULL)
254 
255 htsmsg_t * idnode_slist_enum ( idnode_t *in, idnode_slist_t *options, const char *lang );
256 htsmsg_t * idnode_slist_get ( idnode_t *in, idnode_slist_t *options );
257 int idnode_slist_set ( idnode_t *in, idnode_slist_t *options, const htsmsg_t *vals );
258 char * idnode_slist_rend ( idnode_t *in, idnode_slist_t *options, const char *lang );
259 
260 idnode_list_mapping_t * idnode_list_link
261                        ( idnode_t *in1, idnode_list_head_t *in1_list,
262                          idnode_t *in2, idnode_list_head_t *in2_list,
263                          void *origin, uint32_t savemask );
264 void idnode_list_unlink ( idnode_list_mapping_t *ilm, void *origin );
265 void idnode_list_destroy ( idnode_list_head_t *ilh, void *origin );
266 htsmsg_t * idnode_list_get1 ( idnode_list_head_t *in1_list );
267 htsmsg_t * idnode_list_get2 ( idnode_list_head_t *in2_list );
268 char * idnode_list_get_csv1 ( idnode_list_head_t *in1_list, const char *lang );
269 char * idnode_list_get_csv2 ( idnode_list_head_t *in2_list, const char *lang );
270 int idnode_list_set1 ( idnode_t *in1, idnode_list_head_t *in1_list,
271                        const idclass_t *in2_class, htsmsg_t *in2_list,
272                        int (*in2_create)(idnode_t *in1, idnode_t *in2, void *origin) );
273 int idnode_list_set2 ( idnode_t *in2, idnode_list_head_t *in2_list,
274                        const idclass_t *in1_class, htsmsg_t *in1_list,
275                        int (*in2_create)(idnode_t *in1, idnode_t *in2, void *origin) );
276 
277 const char *idnode_get_str (idnode_t *self, const char *key );
278 int         idnode_get_u32 (idnode_t *self, const char *key, uint32_t *u32);
279 int         idnode_get_s64 (idnode_t *self, const char *key,  int64_t *s64);
280 int         idnode_get_s64_atomic (idnode_t *self, const char *key, int64_t *s64);
281 int         idnode_get_dbl (idnode_t *self, const char *key,   double *dbl);
282 int         idnode_get_bool(idnode_t *self, const char *key, int *b);
283 int         idnode_get_time(idnode_t *self, const char *key, time_t *tm);
284 
285 void idnode_filter_add_str
286   (idnode_filter_t *f, const char *k, const char *v, int t);
287 void idnode_filter_add_num
288   (idnode_filter_t *f, const char *k, int64_t s64, int t, int64_t intsplit);
289 void idnode_filter_add_dbl
290   (idnode_filter_t *f, const char *k, double dbl, int t);
291 void idnode_filter_add_bool
292   (idnode_filter_t *f, const char *k, int b, int t);
293 void idnode_filter_clear
294   (idnode_filter_t *f);
295 int  idnode_filter
296   ( idnode_t *in, idnode_filter_t *filt, const char *lang );
idnode_set_create(int sorted)297 static inline idnode_set_t * idnode_set_create(int sorted)
298   { idnode_set_t *is = calloc(1, sizeof(idnode_set_t));
299     is->is_sorted = sorted; return is; }
300 void idnode_set_alloc ( idnode_set_t *is, size_t alloc );
301 void idnode_set_add
302   ( idnode_set_t *is, idnode_t *in, idnode_filter_t *filt, const char *lang );
303 int idnode_set_remove ( idnode_set_t *is, idnode_t *in );
304 ssize_t idnode_set_find_index( idnode_set_t *is, idnode_t *in );
idnode_set_exists(idnode_set_t * is,idnode_t * in)305 static inline int idnode_set_exists ( idnode_set_t *is, idnode_t *in )
306   { return idnode_set_find_index(is, in) >= 0; }
307 void idnode_set_sort ( idnode_set_t *is, idnode_sort_t *s );
308 void idnode_set_sort_by_title ( idnode_set_t *is, const char *lang );
309 htsmsg_t *idnode_set_as_htsmsg ( idnode_set_t *is );
310 void idnode_set_clear ( idnode_set_t *is );
311 void idnode_set_free ( idnode_set_t *is );
312 
313 #endif /* __TVH_IDNODE_H__ */
314 
315 /******************************************************************************
316  * Editor Configuration
317  *
318  * vim:sts=2:ts=2:sw=2:et
319  *****************************************************************************/
320