ACL/DVR: Rewrite channel tag and add DVR config selection
- remove also obsolete only_tag - accept only uuid for DVR entry config name - try to lock DVR entry when used in dvr_thread
This commit is contained in:
parent
3c64f87d96
commit
7fdf5f1f12
16 changed files with 479 additions and 149 deletions
|
@ -68,13 +68,11 @@ The columns have the following functions:
|
|||
<dd>
|
||||
Enables access to all video recording functions. This also include administration of the auto recordings.
|
||||
|
||||
<dt>All Configs (VR)
|
||||
<dt>DVR Config Profile
|
||||
<dd>
|
||||
Allow to use all DVR configuration profiles. If not set, a DVR
|
||||
configuration profile matched to the authorized user by name is always used
|
||||
(the configuration profile must have same name as the user). If the DVR
|
||||
configuration profile does not exists, the default profile is used.
|
||||
The user is also not allowed to select another profile.
|
||||
If set, the user will only be able to use the DVR config profile
|
||||
equal to this value.
|
||||
Note that this field is unset when the DVR Config Profile is removed.
|
||||
|
||||
<dt>Web interface
|
||||
<dd>
|
||||
|
@ -84,13 +82,6 @@ The columns have the following functions:
|
|||
<dd>
|
||||
Enables access to the Configuration tab.
|
||||
|
||||
<dt>Username Channel Tag Match
|
||||
<dd>
|
||||
If enabled, the user will only be able to access channels with a tag the
|
||||
same name as the username.
|
||||
|
||||
This provides a very rudimentary way of limiting access to certain channels.
|
||||
|
||||
<dt>Min Channel Num
|
||||
<dd>
|
||||
If nonzero, the user will only be able to access channels with
|
||||
|
@ -103,11 +94,9 @@ The columns have the following functions:
|
|||
|
||||
<dt>Channel Tag
|
||||
<dd>
|
||||
If set, the user will only be able to access channels with
|
||||
a channel tag equal to this value. Note that this field stores
|
||||
the tag name (not identified). It means that this field would not be
|
||||
updated when the tag name is changed. A manual re-set of this field
|
||||
is required (for security reasons).
|
||||
If set, the user will only be able to access channels containing
|
||||
this channel tag.
|
||||
Note that this field is unset when the channel tag is removed.
|
||||
|
||||
<dt>Comment
|
||||
<dd>
|
||||
|
|
140
src/access.c
140
src/access.c
|
@ -37,6 +37,7 @@
|
|||
#include "access.h"
|
||||
#include "settings.h"
|
||||
#include "channels.h"
|
||||
#include "dvr/dvr.h"
|
||||
#include "tcp.h"
|
||||
|
||||
struct access_entry_queue access_entries;
|
||||
|
@ -161,6 +162,7 @@ access_destroy(access_t *a)
|
|||
{
|
||||
free(a->aa_username);
|
||||
free(a->aa_representative);
|
||||
htsmsg_destroy(a->aa_dvrcfgs);
|
||||
htsmsg_destroy(a->aa_chtags);
|
||||
free(a);
|
||||
}
|
||||
|
@ -295,10 +297,16 @@ access_update(access_t *a, access_entry_t *ae)
|
|||
}
|
||||
}
|
||||
|
||||
if(ae->ae_chtag && ae->ae_chtag[0] != '\0') {
|
||||
if(ae->ae_dvr_config && ae->ae_dvr_config->dvr_config_name[0] != '\0') {
|
||||
if (a->aa_dvrcfgs == NULL)
|
||||
a->aa_dvrcfgs = htsmsg_create_list();
|
||||
htsmsg_add_str(a->aa_dvrcfgs, NULL, idnode_uuid_as_str(&ae->ae_dvr_config->dvr_id));
|
||||
}
|
||||
|
||||
if(ae->ae_chtag && ae->ae_chtag->ct_name[0] != '\0') {
|
||||
if (a->aa_chtags == NULL)
|
||||
a->aa_chtags = htsmsg_create_list();
|
||||
htsmsg_add_str(a->aa_chtags, NULL, ae->ae_chtag);
|
||||
htsmsg_add_str(a->aa_chtags, NULL, idnode_uuid_as_str(&ae->ae_chtag->ct_id));
|
||||
}
|
||||
|
||||
a->aa_rights |= ae->ae_rights;
|
||||
|
@ -557,12 +565,8 @@ access_entry_update_rights(access_entry_t *ae)
|
|||
r |= ACCESS_ADVANCED_STREAMING;
|
||||
if (ae->ae_dvr)
|
||||
r |= ACCESS_RECORDER;
|
||||
if (ae->ae_dvrallcfg)
|
||||
r |= ACCESS_RECORDER_ALL;
|
||||
if (ae->ae_webui)
|
||||
r |= ACCESS_WEB_INTERFACE;
|
||||
if (ae->ae_tag_only)
|
||||
r |= ACCESS_TAG_ONLY;
|
||||
if (ae->ae_admin)
|
||||
r |= ACCESS_ADMIN;
|
||||
ae->ae_rights = r;
|
||||
|
@ -639,6 +643,11 @@ access_entry_destroy(access_entry_t *ae)
|
|||
TAILQ_REMOVE(&access_entries, ae, ae_link);
|
||||
idnode_unlink(&ae->ae_id);
|
||||
|
||||
if (ae->ae_dvr_config)
|
||||
LIST_REMOVE(ae, ae_dvr_config_link);
|
||||
if (ae->ae_chtag)
|
||||
LIST_REMOVE(ae, ae_channel_tag_link);
|
||||
|
||||
while((ai = TAILQ_FIRST(&ae->ae_ipmasks)) != NULL)
|
||||
{
|
||||
TAILQ_REMOVE(&ae->ae_ipmasks, ai, ai_link);
|
||||
|
@ -653,6 +662,38 @@ access_entry_destroy(access_entry_t *ae)
|
|||
free(ae);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
void
|
||||
access_destroy_by_dvr_config(dvr_config_t *cfg, int delconf)
|
||||
{
|
||||
access_entry_t *ae;
|
||||
|
||||
while ((ae = LIST_FIRST(&cfg->dvr_accesses)) != NULL) {
|
||||
LIST_REMOVE(ae, ae_dvr_config_link);
|
||||
ae->ae_dvr_config = NULL;
|
||||
if (delconf)
|
||||
access_entry_save(ae);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
void
|
||||
access_destroy_by_channel_tag(channel_tag_t *ct, int delconf)
|
||||
{
|
||||
access_entry_t *ae;
|
||||
|
||||
while ((ae = LIST_FIRST(&ct->ct_accesses)) != NULL) {
|
||||
LIST_REMOVE(ae, ae_channel_tag_link);
|
||||
ae->ae_chtag = NULL;
|
||||
if (delconf)
|
||||
access_entry_save(ae);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -806,14 +847,66 @@ access_entry_class_password2_set(void *o, const void *v)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static htsmsg_t *
|
||||
access_entry_chtag_list ( void *o )
|
||||
static int
|
||||
access_entry_chtag_set(void *o, const void *v)
|
||||
{
|
||||
channel_tag_t *ct;
|
||||
htsmsg_t *m = htsmsg_create_list();
|
||||
TAILQ_FOREACH(ct, &channel_tags, ct_link)
|
||||
htsmsg_add_str(m, NULL, ct->ct_name);
|
||||
return m;
|
||||
access_entry_t *ae = (access_entry_t *)o;
|
||||
channel_tag_t *tag = v ? channel_tag_find_by_uuid(v) : NULL;
|
||||
if (tag == NULL && ae->ae_chtag) {
|
||||
LIST_REMOVE(ae, ae_channel_tag_link);
|
||||
ae->ae_chtag = NULL;
|
||||
return 1;
|
||||
} else if (ae->ae_chtag != tag) {
|
||||
if (ae->ae_chtag)
|
||||
LIST_REMOVE(ae, ae_channel_tag_link);
|
||||
ae->ae_chtag = tag;
|
||||
LIST_INSERT_HEAD(&tag->ct_accesses, ae, ae_channel_tag_link);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const void *
|
||||
access_entry_chtag_get(void *o)
|
||||
{
|
||||
static const char *ret;
|
||||
access_entry_t *ae = (access_entry_t *)o;
|
||||
if (ae->ae_chtag)
|
||||
ret = idnode_uuid_as_str(&ae->ae_chtag->ct_id);
|
||||
else
|
||||
ret = "";
|
||||
return &ret;
|
||||
}
|
||||
|
||||
static int
|
||||
access_entry_dvr_config_set(void *o, const void *v)
|
||||
{
|
||||
access_entry_t *ae = (access_entry_t *)o;
|
||||
dvr_config_t *cfg = v ? dvr_config_find_by_uuid(v) : NULL;
|
||||
if (cfg == NULL && ae->ae_dvr_config) {
|
||||
LIST_REMOVE(ae, ae_dvr_config_link);
|
||||
ae->ae_dvr_config = NULL;
|
||||
return 1;
|
||||
} else if (ae->ae_dvr_config != cfg) {
|
||||
if (ae->ae_dvr_config)
|
||||
LIST_REMOVE(ae, ae_dvr_config_link);
|
||||
ae->ae_dvr_config = cfg;
|
||||
LIST_INSERT_HEAD(&cfg->dvr_accesses, ae, ae_dvr_config_link);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const void *
|
||||
access_entry_dvr_config_get(void *o)
|
||||
{
|
||||
static const char *ret;
|
||||
access_entry_t *ae = (access_entry_t *)o;
|
||||
if (ae->ae_dvr_config)
|
||||
ret = idnode_uuid_as_str(&ae->ae_dvr_config->dvr_id);
|
||||
else
|
||||
ret = "";
|
||||
return &ret;
|
||||
}
|
||||
|
||||
const idclass_t access_entry_class = {
|
||||
|
@ -886,10 +979,13 @@ const idclass_t access_entry_class = {
|
|||
.off = offsetof(access_entry_t, ae_dvr),
|
||||
},
|
||||
{
|
||||
.type = PT_BOOL,
|
||||
.id = "dvrallcfg",
|
||||
.name = "All Configs (VR)",
|
||||
.off = offsetof(access_entry_t, ae_dvrallcfg),
|
||||
.type = PT_STR,
|
||||
.id = "dvr_config",
|
||||
.name = "DVR Config Profile",
|
||||
.set = access_entry_dvr_config_set,
|
||||
.get = access_entry_dvr_config_get,
|
||||
.list = dvr_entry_class_config_name_list,
|
||||
.off = offsetof(access_entry_t, ae_dvr_config),
|
||||
},
|
||||
{
|
||||
.type = PT_BOOL,
|
||||
|
@ -903,12 +999,6 @@ const idclass_t access_entry_class = {
|
|||
.name = "Admin",
|
||||
.off = offsetof(access_entry_t, ae_admin),
|
||||
},
|
||||
{
|
||||
.type = PT_BOOL,
|
||||
.id = "tag_only",
|
||||
.name = "Username Channel Tag Match",
|
||||
.off = offsetof(access_entry_t, ae_tag_only),
|
||||
},
|
||||
{
|
||||
.type = PT_U32,
|
||||
.id = "channel_min",
|
||||
|
@ -926,7 +1016,9 @@ const idclass_t access_entry_class = {
|
|||
.id = "channel_tag",
|
||||
.name = "Channel Tag",
|
||||
.off = offsetof(access_entry_t, ae_chtag),
|
||||
.list = access_entry_chtag_list,
|
||||
.set = access_entry_chtag_set,
|
||||
.get = access_entry_chtag_get,
|
||||
.list = channel_tag_class_get_list,
|
||||
},
|
||||
{
|
||||
.type = PT_STR,
|
||||
|
|
32
src/access.h
32
src/access.h
|
@ -22,6 +22,9 @@
|
|||
#include "idnode.h"
|
||||
#include "htsmsg.h"
|
||||
|
||||
struct dvr_config;
|
||||
struct channel_tag;
|
||||
|
||||
typedef struct access_ipmask {
|
||||
TAILQ_ENTRY(access_ipmask) ai_link;
|
||||
|
||||
|
@ -48,18 +51,25 @@ typedef struct access_entry {
|
|||
char *ae_password;
|
||||
char *ae_password2;
|
||||
char *ae_comment;
|
||||
|
||||
int ae_index;
|
||||
int ae_enabled;
|
||||
|
||||
int ae_streaming;
|
||||
int ae_adv_streaming;
|
||||
|
||||
int ae_dvr;
|
||||
int ae_dvrallcfg;
|
||||
struct dvr_config *ae_dvr_config;
|
||||
LIST_ENTRY(access_entry) ae_dvr_config_link;
|
||||
|
||||
int ae_webui;
|
||||
int ae_admin;
|
||||
int ae_tag_only;
|
||||
|
||||
uint32_t ae_chmin;
|
||||
uint32_t ae_chmax;
|
||||
char *ae_chtag;
|
||||
|
||||
struct channel_tag *ae_chtag;
|
||||
LIST_ENTRY(access_entry) ae_channel_tag_link;
|
||||
|
||||
uint32_t ae_rights;
|
||||
|
||||
|
@ -85,6 +95,7 @@ typedef struct access {
|
|||
char *aa_username;
|
||||
char *aa_representative;
|
||||
uint32_t aa_rights;
|
||||
htsmsg_t *aa_dvrcfgs;
|
||||
uint32_t aa_chmin;
|
||||
uint32_t aa_chmax;
|
||||
htsmsg_t *aa_chtags;
|
||||
|
@ -96,14 +107,11 @@ typedef struct access {
|
|||
#define ACCESS_ADVANCED_STREAMING (1<<1)
|
||||
#define ACCESS_WEB_INTERFACE (1<<2)
|
||||
#define ACCESS_RECORDER (1<<3)
|
||||
#define ACCESS_RECORDER_ALL (1<<4)
|
||||
#define ACCESS_TAG_ONLY (1<<5)
|
||||
#define ACCESS_ADMIN (1<<6)
|
||||
#define ACCESS_ADMIN (1<<4)
|
||||
|
||||
#define ACCESS_FULL \
|
||||
(ACCESS_STREAMING | ACCESS_ADVANCED_STREAMING | \
|
||||
ACCESS_WEB_INTERFACE | ACCESS_RECORDER | \
|
||||
ACCESS_RECORDER_ALL | ACCESS_ADMIN)
|
||||
ACCESS_WEB_INTERFACE | ACCESS_RECORDER | ACCESS_ADMIN)
|
||||
|
||||
/**
|
||||
* Create a new ticket for the requested resource and generate a id for it
|
||||
|
@ -165,6 +173,14 @@ access_entry_create(const char *uuid, htsmsg_t *conf);
|
|||
void
|
||||
access_entry_save(access_entry_t *ae);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
access_destroy_by_dvr_config(struct dvr_config *cfg, int delconf);
|
||||
void
|
||||
access_destroy_by_channel_tag(struct channel_tag *ct, int delconf);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -25,21 +25,28 @@
|
|||
static const char *
|
||||
api_dvr_config_name( access_t *perm, const char *config_uuid )
|
||||
{
|
||||
dvr_config_t *cfg;
|
||||
dvr_config_t *cfg = NULL;
|
||||
htsmsg_field_t *f;
|
||||
const char *uuid;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
if (access_verify2(perm, ACCESS_RECORDER_ALL))
|
||||
if (perm->aa_dvrcfgs == NULL)
|
||||
return config_uuid; /* no change */
|
||||
|
||||
cfg = dvr_config_find_by_name(perm->aa_username);
|
||||
if (cfg)
|
||||
return cfg->dvr_config_name;
|
||||
config_uuid = config_uuid ?: "";
|
||||
HTSMSG_FOREACH(f, perm->aa_dvrcfgs) {
|
||||
uuid = htsmsg_field_get_str(f) ?: "";
|
||||
if (strcmp(uuid, config_uuid) == 0)
|
||||
return config_uuid;
|
||||
if (!cfg)
|
||||
cfg = dvr_config_find_by_uuid(uuid);
|
||||
}
|
||||
|
||||
if (perm->aa_username)
|
||||
tvhlog(LOG_INFO, "dvr", "User '%s' has no dvr config with identical name, using default...", perm->aa_username);
|
||||
if (!cfg && perm->aa_username)
|
||||
tvhlog(LOG_INFO, "dvr", "User '%s' has no valid dvr config in ACL, using default...", perm->aa_username);
|
||||
|
||||
return NULL; /* default */
|
||||
return cfg ? idnode_uuid_as_str(&cfg->dvr_id) : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -71,9 +78,6 @@ api_dvr_config_create
|
|||
return EINVAL;
|
||||
if (s[0] == '\0')
|
||||
return EINVAL;
|
||||
if (access_verify2(perm, ACCESS_ADMIN) &&
|
||||
access_verify2(perm, ACCESS_RECORDER_ALL | ACCESS_RECORDER))
|
||||
return EACCES;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
if ((cfg = dvr_config_create(NULL, NULL, conf)))
|
||||
|
@ -153,16 +157,20 @@ api_dvr_entry_create
|
|||
{
|
||||
dvr_entry_t *de;
|
||||
htsmsg_t *conf;
|
||||
const char *s1, *s2;
|
||||
|
||||
if (!(conf = htsmsg_get_map(args, "conf")))
|
||||
return EINVAL;
|
||||
|
||||
if (access_verify2(perm, ACCESS_RECORDER_ALL)) {
|
||||
pthread_mutex_lock(&global_lock);
|
||||
s1 = htsmsg_get_str(conf, "config_name");
|
||||
s2 = api_dvr_config_name(perm, s1);
|
||||
if (strcmp(s1 ?: "", s2 ?: "")) {
|
||||
htsmsg_delete_field(conf, "config_name");
|
||||
htsmsg_add_str(conf, "config_name", perm->aa_username ?: "");
|
||||
if (s2)
|
||||
htsmsg_add_str(conf, "config_name", s2);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
if ((de = dvr_entry_create(NULL, conf)))
|
||||
dvr_entry_save(de);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
|
|
@ -163,19 +163,6 @@ channel_class_tags_set ( void *obj, const void *p )
|
|||
return channel_set_tags_by_list(obj, (htsmsg_t*)p);
|
||||
}
|
||||
|
||||
static htsmsg_t *
|
||||
channel_class_tags_enum ( void *obj )
|
||||
{
|
||||
htsmsg_t *e, *m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "type", "api");
|
||||
htsmsg_add_str(m, "uri", "channeltag/list");
|
||||
htsmsg_add_str(m, "event", "channeltag");
|
||||
e = htsmsg_create_map();
|
||||
htsmsg_add_bool(e, "enum", 1);
|
||||
htsmsg_add_msg(m, "params", e);
|
||||
return m;
|
||||
}
|
||||
|
||||
static void
|
||||
channel_class_icon_notify ( void *obj )
|
||||
{
|
||||
|
@ -369,7 +356,7 @@ const idclass_t channel_class = {
|
|||
.name = "Tags",
|
||||
.get = channel_class_tags_get,
|
||||
.set = channel_class_tags_set,
|
||||
.list = channel_class_tags_enum,
|
||||
.list = channel_tag_class_get_list,
|
||||
.rend = channel_class_tags_rend
|
||||
},
|
||||
{}
|
||||
|
@ -430,7 +417,8 @@ channel_access(channel_t *ch, access_t *a, const char *username)
|
|||
htsmsg_field_t *f;
|
||||
HTSMSG_FOREACH(f, a->aa_chtags) {
|
||||
LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link) {
|
||||
if (!strcmp(htsmsg_field_get_str(f) ?: "", ctm->ctm_tag->ct_name))
|
||||
if (!strcmp(htsmsg_field_get_str(f) ?: "",
|
||||
idnode_uuid_as_str(&ctm->ctm_tag->ct_id)))
|
||||
goto chtags_ok;
|
||||
}
|
||||
}
|
||||
|
@ -438,17 +426,6 @@ channel_access(channel_t *ch, access_t *a, const char *username)
|
|||
}
|
||||
chtags_ok:
|
||||
|
||||
/* Channel tag <-> user name match */
|
||||
if (ch && (a->aa_rights & ACCESS_TAG_ONLY) != 0) {
|
||||
channel_tag_mapping_t *ctm;
|
||||
LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link) {
|
||||
if (!strcmp(username ?: "", ctm->ctm_tag->ct_name))
|
||||
goto tagonly_ok;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
tagonly_ok:
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -761,6 +738,9 @@ channel_tag_create(const char *uuid, htsmsg_t *conf)
|
|||
channel_tag_t *ct;
|
||||
|
||||
ct = calloc(1, sizeof(channel_tag_t));
|
||||
LIST_INIT(&ct->ct_ctms);
|
||||
LIST_INIT(&ct->ct_autorecs);
|
||||
LIST_INIT(&ct->ct_accesses);
|
||||
|
||||
if (idnode_insert(&ct->ct_id, uuid, &channel_tag_class, IDNODE_SHORT_UUID)) {
|
||||
if (uuid)
|
||||
|
@ -807,6 +787,9 @@ channel_tag_destroy(channel_tag_t *ct, int delconf)
|
|||
TAILQ_REMOVE(&channel_tags, ct, ct_link);
|
||||
idnode_unlink(&ct->ct_id);
|
||||
|
||||
autorec_destroy_by_channel_tag(ct, delconf);
|
||||
access_destroy_by_channel_tag(ct, delconf);
|
||||
|
||||
free(ct->ct_name);
|
||||
free(ct->ct_comment);
|
||||
free(ct->ct_icon);
|
||||
|
@ -849,6 +832,17 @@ channel_tag_class_get_title (idnode_t *self)
|
|||
return ct->ct_name ?: "";
|
||||
}
|
||||
|
||||
/* exported for others */
|
||||
htsmsg_t *
|
||||
channel_tag_class_get_list(void *o)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "type", "api");
|
||||
htsmsg_add_str(m, "uri", "channeltag/list");
|
||||
htsmsg_add_str(m, "event", "channeltag");
|
||||
return m;
|
||||
}
|
||||
|
||||
const idclass_t channel_tag_class = {
|
||||
.ic_class = "channeltag",
|
||||
.ic_caption = "Channel Tag",
|
||||
|
|
|
@ -95,6 +95,8 @@ typedef struct channel_tag {
|
|||
|
||||
struct dvr_autorec_entry_list ct_autorecs;
|
||||
|
||||
struct access_entry_list ct_accesses;
|
||||
|
||||
int ct_htsp_id;
|
||||
|
||||
} channel_tag_t;
|
||||
|
@ -164,6 +166,8 @@ static inline channel_tag_t *channel_tag_find_by_uuid(const char *uuid)
|
|||
|
||||
void channel_tag_save(channel_tag_t *ct);
|
||||
|
||||
htsmsg_t * channel_tag_class_get_list(void *o);
|
||||
|
||||
int channel_access(channel_t *ch, struct access *a, const char *username);
|
||||
|
||||
int channel_tag_map(channel_t *ch, channel_tag_t *ct);
|
||||
|
|
104
src/config.c
104
src/config.c
|
@ -853,6 +853,109 @@ config_migrate_v10 ( void )
|
|||
config_migrate_move("channeltags", "channel/tag");
|
||||
}
|
||||
|
||||
static const char *
|
||||
config_find_uuid( htsmsg_t *map, const char *name, const char *value )
|
||||
{
|
||||
htsmsg_t *e;
|
||||
htsmsg_field_t *f;
|
||||
const char *s;
|
||||
|
||||
HTSMSG_FOREACH(f, map) {
|
||||
if (!(e = htsmsg_field_get_map(f))) continue;
|
||||
if ((s = htsmsg_get_str(e, name)) != NULL) {
|
||||
if (!strcmp(s, value))
|
||||
return f->hmf_name;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
config_modify_acl_dvallcfg( htsmsg_t *c, htsmsg_t *dvr_config )
|
||||
{
|
||||
uint32_t a;
|
||||
const char *username, *uuid;
|
||||
|
||||
username = htsmsg_get_str(c, "username");
|
||||
if (!htsmsg_get_u32(c, "dvallcfg", &a))
|
||||
if (a == 0) {
|
||||
uuid = username ? config_find_uuid(dvr_config, "name", username) : NULL;
|
||||
if (uuid)
|
||||
htsmsg_add_str(c, "dvr_config", uuid);
|
||||
}
|
||||
htsmsg_delete_field(c, "dvallcfg");
|
||||
}
|
||||
|
||||
static void
|
||||
config_modify_acl_tag_only( htsmsg_t *c, htsmsg_t *channel_tag )
|
||||
{
|
||||
uint32_t a;
|
||||
const char *username, *tag, *uuid;
|
||||
|
||||
username = htsmsg_get_str(c, "username");
|
||||
tag = htsmsg_get_str(c, "channel_tag");
|
||||
if (!tag || tag[0] == '\0')
|
||||
tag = NULL;
|
||||
if (tag == NULL && !htsmsg_get_u32(c, "tag_only", &a)) {
|
||||
if (a) {
|
||||
uuid = username ? config_find_uuid(channel_tag, "name", username) : NULL;
|
||||
if (uuid)
|
||||
htsmsg_add_str(c, "channel_tag", uuid);
|
||||
}
|
||||
} else if (tag) {
|
||||
uuid = config_find_uuid(channel_tag, "name", tag);
|
||||
if (uuid) {
|
||||
htsmsg_delete_field(c, "channel_tag");
|
||||
htsmsg_add_str(c, "channel_tag", uuid);
|
||||
}
|
||||
}
|
||||
htsmsg_delete_field(c, "tag_only");
|
||||
}
|
||||
|
||||
static void
|
||||
config_modify_dvr_config_name( htsmsg_t *c, htsmsg_t *dvr_config )
|
||||
{
|
||||
const char *config_name, *uuid;
|
||||
|
||||
config_name = htsmsg_get_str(c, "config_name");
|
||||
uuid = config_name ? config_find_uuid(dvr_config, "name", config_name) : NULL;
|
||||
htsmsg_delete_field(c, "config_name");
|
||||
htsmsg_add_str(c, "config_name", uuid ?: "");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
config_migrate_v11 ( void )
|
||||
{
|
||||
htsmsg_t *dvr_config;
|
||||
htsmsg_t *channel_tag;
|
||||
htsmsg_t *c, *e;
|
||||
htsmsg_field_t *f;
|
||||
|
||||
dvr_config = hts_settings_load("dvr/config");
|
||||
channel_tag = hts_settings_load("channel/tag");
|
||||
|
||||
if ((c = hts_settings_load("accesscontrol")) != NULL) {
|
||||
HTSMSG_FOREACH(f, c) {
|
||||
if (!(e = htsmsg_field_get_map(f))) continue;
|
||||
config_modify_acl_dvallcfg(e, dvr_config);
|
||||
config_modify_acl_tag_only(e, channel_tag);
|
||||
}
|
||||
htsmsg_destroy(c);
|
||||
}
|
||||
|
||||
if ((c = hts_settings_load("dvr/log")) != NULL) {
|
||||
HTSMSG_FOREACH(f, c) {
|
||||
if (!(e = htsmsg_field_get_map(f))) continue;
|
||||
config_modify_dvr_config_name(e, dvr_config);
|
||||
}
|
||||
htsmsg_destroy(c);
|
||||
}
|
||||
|
||||
htsmsg_destroy(channel_tag);
|
||||
htsmsg_destroy(dvr_config);
|
||||
}
|
||||
|
||||
/*
|
||||
* Migration table
|
||||
*/
|
||||
|
@ -867,6 +970,7 @@ static const config_migrate_t config_migrate_table[] = {
|
|||
config_migrate_v8,
|
||||
config_migrate_v9,
|
||||
config_migrate_v10,
|
||||
config_migrate_v11
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
typedef struct dvr_config {
|
||||
idnode_t dvr_id;
|
||||
|
||||
LIST_ENTRY(dvr_config) config_link;
|
||||
|
||||
int dvr_enabled;
|
||||
|
@ -72,6 +73,10 @@ typedef struct dvr_config {
|
|||
/* Duplicate detect */
|
||||
int dvr_dup_detect_episode;
|
||||
|
||||
struct dvr_entry_list dvr_entries;
|
||||
|
||||
struct access_entry_list dvr_accesses;
|
||||
|
||||
} dvr_config_t;
|
||||
|
||||
extern struct dvr_config_list dvrconfigs;
|
||||
|
@ -150,7 +155,7 @@ typedef struct dvr_entry {
|
|||
*/
|
||||
|
||||
dvr_config_t *de_config;
|
||||
char *de_config_name;
|
||||
LIST_ENTRY(dvr_entry) de_config_link;
|
||||
|
||||
time_t de_start;
|
||||
time_t de_stop;
|
||||
|
@ -185,6 +190,7 @@ typedef struct dvr_entry {
|
|||
* Recording state (onyl valid if de_sched_state == DVR_RECORDING)
|
||||
*/
|
||||
dvr_rs_state_t de_rec_state;
|
||||
int de_locked;
|
||||
|
||||
/**
|
||||
* Number of errors (only to be modified by the recording thread)
|
||||
|
@ -346,6 +352,7 @@ dvr_entry_update( dvr_entry_t *de,
|
|||
time_t de_start_extra, time_t de_stop_extra );
|
||||
|
||||
void dvr_init(void);
|
||||
void dvr_config_init(void);
|
||||
|
||||
void dvr_done(void);
|
||||
|
||||
|
@ -438,6 +445,8 @@ void dvr_autorec_check_serieslink(epg_serieslink_t *s);
|
|||
|
||||
void autorec_destroy_by_channel(channel_t *ch, int delconf);
|
||||
|
||||
void autorec_destroy_by_channel_tag(channel_tag_t *ct, int delconf);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -392,18 +392,6 @@ dvr_autorec_entry_class_tag_get(void *o)
|
|||
return &ret;
|
||||
}
|
||||
|
||||
static htsmsg_t *
|
||||
dvr_autorec_entry_class_tag_list(void *o)
|
||||
{
|
||||
htsmsg_t *e, *m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "type", "api");
|
||||
htsmsg_add_str(m, "uri", "channeltag/list");
|
||||
htsmsg_add_str(m, "event", "channeltag");
|
||||
e = htsmsg_create_map();
|
||||
htsmsg_add_msg(m, "params", e);
|
||||
return m;
|
||||
}
|
||||
|
||||
static int
|
||||
dvr_autorec_entry_class_time_set(void *o, const void *v, int *tm)
|
||||
{
|
||||
|
@ -726,7 +714,7 @@ const idclass_t dvr_autorec_entry_class = {
|
|||
.name = "Channel Tag",
|
||||
.set = dvr_autorec_entry_class_tag_set,
|
||||
.get = dvr_autorec_entry_class_tag_get,
|
||||
.list = dvr_autorec_entry_class_tag_list,
|
||||
.list = channel_tag_class_get_list,
|
||||
},
|
||||
{
|
||||
.type = PT_STR,
|
||||
|
@ -913,7 +901,7 @@ dvr_autorec_changed(dvr_autorec_entry_t *dae, int purge)
|
|||
CHANNEL_FOREACH(ch) {
|
||||
RB_FOREACH(e, &ch->ch_epg_schedule, sched_link) {
|
||||
if(autorec_cmp(dae, e))
|
||||
dvr_entry_create_by_autorec(e, dae);
|
||||
dvr_entry_create_by_autorec(e, dae);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -936,3 +924,25 @@ autorec_destroy_by_channel(channel_t *ch, int delconf)
|
|||
htsmsg_add_u32(m, "reload", 1);
|
||||
notify_by_msg("autorec", m);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
void
|
||||
autorec_destroy_by_channel_tag(channel_tag_t *ct, int delconf)
|
||||
{
|
||||
dvr_autorec_entry_t *dae;
|
||||
htsmsg_t *m;
|
||||
|
||||
while((dae = LIST_FIRST(&ct->ct_autorecs)) != NULL) {
|
||||
LIST_REMOVE(dae, dae_channel_tag_link);
|
||||
dae->dae_channel_tag = NULL;
|
||||
if (delconf)
|
||||
dvr_autorec_save(dae);
|
||||
}
|
||||
|
||||
/* Notify web clients that we have messed with the tables */
|
||||
m = htsmsg_create_map();
|
||||
htsmsg_add_u32(m, "reload", 1);
|
||||
notify_by_msg("autorec", m);
|
||||
}
|
||||
|
|
147
src/dvr/dvr_db.c
147
src/dvr/dvr_db.c
|
@ -43,7 +43,7 @@ struct dvr_entry_list dvrentries;
|
|||
static gtimer_t dvr_dbus_timer;
|
||||
#endif
|
||||
|
||||
static void dvr_entry_remove(dvr_entry_t *de, int delconf);
|
||||
static void dvr_entry_destroy(dvr_entry_t *de, int delconf);
|
||||
static void dvr_timer_expire(void *aux);
|
||||
static void dvr_timer_start_recording(void *aux);
|
||||
static void dvr_timer_stop_recording(void *aux);
|
||||
|
@ -421,7 +421,7 @@ dvr_entry_create(const char *uuid, htsmsg_t *conf)
|
|||
if(de2 != de &&
|
||||
de2->de_start == de->de_start &&
|
||||
de2->de_sched_state != DVR_COMPLETED) {
|
||||
dvr_entry_remove(de, 0);
|
||||
dvr_entry_destroy(de, 0);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -524,7 +524,11 @@ dvr_entry_create_htsp(const char *config_uuid,
|
|||
const char *creator, dvr_autorec_entry_t *dae,
|
||||
dvr_prio_t pri)
|
||||
{
|
||||
return _dvr_entry_create(config_uuid, NULL,
|
||||
dvr_config_t *cfg = dvr_config_find_by_uuid(config_uuid);
|
||||
if (!cfg)
|
||||
cfg = dvr_config_find_by_name(config_uuid);
|
||||
return _dvr_entry_create(cfg ? idnode_uuid_as_str(&cfg->dvr_id) : NULL,
|
||||
NULL,
|
||||
ch, start, stop, start_extra, stop_extra,
|
||||
title, description, lang, content_type,
|
||||
creator, dae, pri);
|
||||
|
@ -625,8 +629,10 @@ dvr_entry_dec_ref(dvr_entry_t *de)
|
|||
if(de->de_autorec != NULL)
|
||||
LIST_REMOVE(de, de_autorec_link);
|
||||
|
||||
if(de->de_config != NULL)
|
||||
LIST_REMOVE(de, de_config_link);
|
||||
|
||||
free(de->de_filename);
|
||||
free(de->de_config_name);
|
||||
free(de->de_creator);
|
||||
if (de->de_title) lang_str_destroy(de->de_title);
|
||||
if (de->de_desc) lang_str_destroy(de->de_desc);
|
||||
|
@ -639,7 +645,7 @@ dvr_entry_dec_ref(dvr_entry_t *de)
|
|||
*
|
||||
*/
|
||||
static void
|
||||
dvr_entry_remove(dvr_entry_t *de, int delconf)
|
||||
dvr_entry_destroy(dvr_entry_t *de, int delconf)
|
||||
{
|
||||
if (delconf)
|
||||
hts_settings_remove("dvr/log/%s", idnode_uuid_as_str(&de->de_id));
|
||||
|
@ -665,6 +671,27 @@ dvr_entry_remove(dvr_entry_t *de, int delconf)
|
|||
dvr_entry_dec_ref(de);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
dvr_entry_destroy_by_config(dvr_config_t *cfg, int delconf)
|
||||
{
|
||||
dvr_entry_t *de;
|
||||
dvr_config_t *def = NULL;
|
||||
|
||||
while ((de = LIST_FIRST(&cfg->dvr_entries)) != NULL) {
|
||||
LIST_REMOVE(de, de_config_link);
|
||||
if (!def)
|
||||
def = dvr_config_find_by_name_default("");
|
||||
de->de_config = def;
|
||||
if (def)
|
||||
LIST_INSERT_HEAD(&def->dvr_entries, de, de_config_link);
|
||||
if (delconf)
|
||||
dvr_entry_save(de);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -707,7 +734,7 @@ static void
|
|||
dvr_timer_expire(void *aux)
|
||||
{
|
||||
dvr_entry_t *de = aux;
|
||||
dvr_entry_remove(de, 1);
|
||||
dvr_entry_destroy(de, 1);
|
||||
|
||||
}
|
||||
|
||||
|
@ -718,6 +745,9 @@ static dvr_entry_t *_dvr_entry_update
|
|||
{
|
||||
int save = 0;
|
||||
|
||||
if (de->de_locked)
|
||||
return de;
|
||||
|
||||
/* Start/Stop */
|
||||
if (e) {
|
||||
start = e->start;
|
||||
|
@ -836,7 +866,7 @@ dvr_event_replaced(epg_broadcast_t *e, epg_broadcast_t *new_e)
|
|||
|
||||
/* If this was craeted by autorec - just remove it, it'll get recreated */
|
||||
if (de->de_autorec) {
|
||||
dvr_entry_remove(de, 1);
|
||||
dvr_entry_destroy(de, 1);
|
||||
|
||||
/* Find match */
|
||||
} else {
|
||||
|
@ -1006,7 +1036,7 @@ dvr_entry_cancel(dvr_entry_t *de)
|
|||
{
|
||||
switch(de->de_sched_state) {
|
||||
case DVR_SCHEDULED:
|
||||
dvr_entry_remove(de, 1);
|
||||
dvr_entry_destroy(de, 1);
|
||||
return NULL;
|
||||
|
||||
case DVR_RECORDING:
|
||||
|
@ -1015,11 +1045,11 @@ dvr_entry_cancel(dvr_entry_t *de)
|
|||
return de;
|
||||
|
||||
case DVR_COMPLETED:
|
||||
dvr_entry_remove(de, 1);
|
||||
dvr_entry_destroy(de, 1);
|
||||
return NULL;
|
||||
|
||||
case DVR_MISSED_TIME:
|
||||
dvr_entry_remove(de, 1);
|
||||
dvr_entry_destroy(de, 1);
|
||||
return NULL;
|
||||
|
||||
default:
|
||||
|
@ -1052,7 +1082,10 @@ dvr_entry_class_save(idnode_t *self)
|
|||
static void
|
||||
dvr_entry_class_delete(idnode_t *self)
|
||||
{
|
||||
dvr_entry_remove((dvr_entry_t *)self, 1);
|
||||
dvr_entry_t *de = (dvr_entry_t *)self;
|
||||
if (de->de_locked)
|
||||
return;
|
||||
dvr_entry_destroy(de, 1);
|
||||
}
|
||||
|
||||
static const char *
|
||||
|
@ -1070,25 +1103,52 @@ static int
|
|||
dvr_entry_class_config_name_set(void *o, const void *v)
|
||||
{
|
||||
dvr_entry_t *de = (dvr_entry_t *)o;
|
||||
const char *s = v ?: "";
|
||||
if (strcmp(s, de->de_config_name ?: "")) {
|
||||
free(de->de_config_name);
|
||||
de->de_config_name = strdup(v);
|
||||
de->de_config = dvr_config_find_by_name_default(de->de_config_name);
|
||||
dvr_config_t *cfg;
|
||||
|
||||
if (de->de_locked)
|
||||
return 0;
|
||||
cfg = v ? dvr_config_find_by_uuid(v) : NULL;
|
||||
if (!cfg)
|
||||
cfg = dvr_config_find_by_name_default("");
|
||||
if (cfg == NULL) {
|
||||
if (de->de_config) {
|
||||
LIST_REMOVE(de, de_config_link);
|
||||
de->de_config = NULL;
|
||||
return 1;
|
||||
}
|
||||
} else if (de->de_config != cfg) {
|
||||
if (de->de_config)
|
||||
LIST_REMOVE(de, de_config_link);
|
||||
de->de_config = cfg;
|
||||
LIST_INSERT_HEAD(&cfg->dvr_entries, de, de_config_link);
|
||||
return 1;
|
||||
}
|
||||
/* for sure */
|
||||
de->de_config = dvr_config_find_by_name_default(de->de_config_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const void *
|
||||
dvr_entry_class_config_name_get(void *o)
|
||||
{
|
||||
static const char *ret;
|
||||
dvr_entry_t *de = (dvr_entry_t *)o;
|
||||
if (de->de_config)
|
||||
ret = idnode_uuid_as_str(&de->de_config->dvr_id);
|
||||
else
|
||||
ret = "";
|
||||
return &ret;
|
||||
}
|
||||
|
||||
static int
|
||||
dvr_entry_class_channel_set(void *o, const void *v)
|
||||
{
|
||||
dvr_entry_t *de = (dvr_entry_t *)o;
|
||||
channel_t *ch = v ? channel_find_by_uuid(v) : NULL;
|
||||
if (!de->de_config_name)
|
||||
dvr_entry_class_config_name_set(o, "");
|
||||
channel_t *ch;
|
||||
|
||||
if (de->de_locked)
|
||||
return 0;
|
||||
ch = v ? channel_find_by_uuid(v) : NULL;
|
||||
if (!de->de_config)
|
||||
de->de_config = dvr_config_find_by_name_default("");
|
||||
if (ch == NULL) {
|
||||
if (de->de_channel) {
|
||||
LIST_REMOVE(de, de_channel_link);
|
||||
|
@ -1134,8 +1194,10 @@ dvr_entry_class_channel_name_set(void *o, const void *v)
|
|||
{
|
||||
dvr_entry_t *de = (dvr_entry_t *)o;
|
||||
channel_t *ch;
|
||||
if (!de->de_config_name)
|
||||
dvr_entry_class_config_name_set(o, "");
|
||||
if (de->de_locked)
|
||||
return 0;
|
||||
if (!de->de_config)
|
||||
de->de_config = dvr_config_find_by_name_default("");
|
||||
if (!strcmp(de->de_channel_name ?: "", v ?: ""))
|
||||
return 0;
|
||||
ch = v ? channel_find_by_name(v) : NULL;
|
||||
|
@ -1629,8 +1691,8 @@ const idclass_t dvr_entry_class = {
|
|||
.id = "config_name",
|
||||
.name = "DVR Configuration",
|
||||
.set = dvr_entry_class_config_name_set,
|
||||
.get = dvr_entry_class_config_name_get,
|
||||
.list = dvr_entry_class_config_name_list,
|
||||
.off = offsetof(dvr_entry_t, de_config_name),
|
||||
},
|
||||
{
|
||||
.type = PT_STR,
|
||||
|
@ -1813,6 +1875,8 @@ dvr_config_create(const char *name, const char *uuid, htsmsg_t *conf)
|
|||
name = "";
|
||||
|
||||
cfg = calloc(1, sizeof(dvr_config_t));
|
||||
LIST_INIT(&cfg->dvr_entries);
|
||||
LIST_INIT(&cfg->dvr_accesses);
|
||||
|
||||
if (idnode_insert(&cfg->dvr_id, uuid, &dvr_config_class, 0)) {
|
||||
if (uuid)
|
||||
|
@ -1872,6 +1936,10 @@ dvr_config_destroy(dvr_config_t *cfg, int delconf)
|
|||
}
|
||||
LIST_REMOVE(cfg, config_link);
|
||||
idnode_unlink(&cfg->dvr_id);
|
||||
|
||||
dvr_entry_destroy_by_config(cfg, delconf);
|
||||
access_destroy_by_dvr_config(cfg, delconf);
|
||||
|
||||
free(cfg->dvr_charset_id);
|
||||
free(cfg->dvr_charset);
|
||||
free(cfg->dvr_storage);
|
||||
|
@ -1962,12 +2030,23 @@ static int
|
|||
dvr_config_class_perm(idnode_t *self, access_t *a, htsmsg_t *msg_to_write)
|
||||
{
|
||||
dvr_config_t *cfg = (dvr_config_t *)self;
|
||||
htsmsg_field_t *f;
|
||||
const char *uuid, *my_uuid;
|
||||
|
||||
if (access_verify2(a, ACCESS_RECORDER))
|
||||
return -1;
|
||||
if (!access_verify2(a, ACCESS_ADMIN))
|
||||
return 0;
|
||||
if (access_verify2(a, ACCESS_RECORDER_ALL))
|
||||
return 0;
|
||||
if (a->aa_dvrcfgs) {
|
||||
my_uuid = idnode_uuid_as_str(&cfg->dvr_id);
|
||||
HTSMSG_FOREACH(f, a->aa_dvrcfgs) {
|
||||
uuid = htsmsg_field_get_str(f) ?: "";
|
||||
if (!strcmp(uuid, my_uuid))
|
||||
goto fine;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
fine:
|
||||
if (strcmp(cfg->dvr_config_name ?: "", a->aa_username ?: ""))
|
||||
return -1;
|
||||
return 0;
|
||||
|
@ -2433,7 +2512,7 @@ dvr_entry_delete(dvr_entry_t *de)
|
|||
}
|
||||
|
||||
}
|
||||
dvr_entry_remove(de, 1);
|
||||
dvr_entry_destroy(de, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2444,7 +2523,7 @@ dvr_entry_cancel_delete(dvr_entry_t *de)
|
|||
{
|
||||
switch(de->de_sched_state) {
|
||||
case DVR_SCHEDULED:
|
||||
dvr_entry_remove(de, 1);
|
||||
dvr_entry_destroy(de, 1);
|
||||
break;
|
||||
|
||||
case DVR_RECORDING:
|
||||
|
@ -2455,7 +2534,7 @@ dvr_entry_cancel_delete(dvr_entry_t *de)
|
|||
break;
|
||||
|
||||
case DVR_MISSED_TIME:
|
||||
dvr_entry_remove(de, 1);
|
||||
dvr_entry_destroy(de, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -2467,7 +2546,7 @@ dvr_entry_cancel_delete(dvr_entry_t *de)
|
|||
*
|
||||
*/
|
||||
void
|
||||
dvr_init(void)
|
||||
dvr_config_init(void)
|
||||
{
|
||||
htsmsg_t *m, *l;
|
||||
htsmsg_field_t *f;
|
||||
|
@ -2520,7 +2599,11 @@ dvr_init(void)
|
|||
cfg->dvr_config_name, cfg->dvr_storage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dvr_init(void)
|
||||
{
|
||||
#if ENABLE_INOTIFY
|
||||
dvr_inotify_init();
|
||||
#endif
|
||||
|
@ -2542,10 +2625,10 @@ dvr_done(void)
|
|||
dvr_inotify_done();
|
||||
#endif
|
||||
pthread_mutex_lock(&global_lock);
|
||||
while ((de = LIST_FIRST(&dvrentries)) != NULL)
|
||||
dvr_entry_destroy(de, 0);
|
||||
while ((cfg = LIST_FIRST(&dvrconfigs)) != NULL)
|
||||
dvr_config_destroy(cfg, 0);
|
||||
while ((de = LIST_FIRST(&dvrentries)) != NULL)
|
||||
dvr_entry_remove(de, 0);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
dvr_autorec_done();
|
||||
}
|
||||
|
|
|
@ -66,6 +66,9 @@ dvr_rec_subscribe(dvr_entry_t *de)
|
|||
int flags;
|
||||
|
||||
assert(de->de_s == NULL);
|
||||
assert(!de->de_locked);
|
||||
|
||||
de->de_locked = 1;
|
||||
|
||||
if(de->de_pri < 5)
|
||||
weight = prio2weight[de->de_pri];
|
||||
|
@ -117,6 +120,8 @@ dvr_rec_unsubscribe(dvr_entry_t *de, int stopcode)
|
|||
globalheaders_destroy(de->de_gh);
|
||||
|
||||
de->de_last_error = stopcode;
|
||||
|
||||
de->de_locked = 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -177,7 +182,10 @@ pvr_generate_filename(dvr_entry_t *de, const streaming_start_t *ss)
|
|||
struct stat st;
|
||||
char *filename, *s;
|
||||
struct tm tm;
|
||||
dvr_config_t *cfg = dvr_config_find_by_name_default(de->de_config_name);
|
||||
dvr_config_t *cfg = de->de_config;
|
||||
|
||||
if (de == NULL)
|
||||
return -1;
|
||||
|
||||
strncpy(path, cfg->dvr_storage, sizeof(path));
|
||||
path[sizeof(path)-1] = '\0';
|
||||
|
@ -304,9 +312,14 @@ dvr_rec_start(dvr_entry_t *de, const streaming_start_t *ss)
|
|||
const source_info_t *si = &ss->ss_si;
|
||||
const streaming_start_component_t *ssc;
|
||||
int i;
|
||||
dvr_config_t *cfg = dvr_config_find_by_name_default(de->de_config_name);
|
||||
dvr_config_t *cfg = de->de_config;
|
||||
muxer_container_type_t mc;
|
||||
|
||||
if (!cfg) {
|
||||
dvr_rec_fatal_error(de, "Unable to determine config profile");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mc = dvr_entry_get_mc(de);
|
||||
|
||||
de->de_mux = muxer_create(mc, &cfg->dvr_muxcnf);
|
||||
|
@ -427,7 +440,7 @@ static void *
|
|||
dvr_thread(void *aux)
|
||||
{
|
||||
dvr_entry_t *de = aux;
|
||||
dvr_config_t *cfg = dvr_config_find_by_name_default(de->de_config_name);
|
||||
dvr_config_t *cfg = de->de_config;
|
||||
streaming_queue_t *sq = &de->de_sq;
|
||||
streaming_message_t *sm;
|
||||
th_pkt_t *pkt;
|
||||
|
@ -666,7 +679,7 @@ dvr_thread_epilog(dvr_entry_t *de)
|
|||
muxer_destroy(de->de_mux);
|
||||
de->de_mux = NULL;
|
||||
|
||||
dvr_config_t *cfg = dvr_config_find_by_name_default(de->de_config_name);
|
||||
if(cfg->dvr_postproc && de->de_filename)
|
||||
dvr_config_t *cfg = de->de_config;
|
||||
if(cfg && cfg->dvr_postproc && de->de_filename)
|
||||
dvr_spawn_postproc(de,cfg->dvr_postproc);
|
||||
}
|
||||
|
|
|
@ -652,7 +652,6 @@ htsp_build_dvrentry(dvr_entry_t *de, const char *method)
|
|||
htsmsg_t *out = htsmsg_create_map();
|
||||
const char *s = NULL, *error = NULL;
|
||||
const char *p;
|
||||
dvr_config_t *cfg;
|
||||
|
||||
htsmsg_add_u32(out, "id", idnode_get_short_uuid(&de->de_id));
|
||||
if (de->de_channel)
|
||||
|
@ -666,11 +665,9 @@ htsp_build_dvrentry(dvr_entry_t *de, const char *method)
|
|||
if( de->de_desc && (s = lang_str_get(de->de_desc, NULL)))
|
||||
htsmsg_add_str(out, "description", s);
|
||||
|
||||
if( de->de_filename && de->de_config_name ) {
|
||||
if ((cfg = dvr_config_find_by_name_default(de->de_config_name))) {
|
||||
if ((p = tvh_strbegins(de->de_filename, cfg->dvr_storage)))
|
||||
htsmsg_add_str(out, "path", p);
|
||||
}
|
||||
if( de->de_filename && de->de_config ) {
|
||||
if ((p = tvh_strbegins(de->de_filename, de->de_config->dvr_storage)))
|
||||
htsmsg_add_str(out, "path", p);
|
||||
}
|
||||
|
||||
switch(de->de_sched_state) {
|
||||
|
|
|
@ -227,7 +227,7 @@ idnode_get_short_uuid (const idnode_t *in)
|
|||
const char *
|
||||
idnode_uuid_as_str(const idnode_t *in)
|
||||
{
|
||||
static tvh_uuid_t ret[16];
|
||||
static tvh_uuid_t __thread ret[16];
|
||||
static uint8_t p = 0;
|
||||
bin2hex(ret[p].hex, sizeof(ret[p].hex), in->in_uuid, sizeof(in->in_uuid));
|
||||
const char *s = ret[p].hex;
|
||||
|
|
|
@ -821,6 +821,8 @@ main(int argc, char **argv)
|
|||
|
||||
subscription_init();
|
||||
|
||||
dvr_config_init();
|
||||
|
||||
access_init(opt_firstrun, opt_noacl);
|
||||
|
||||
#if ENABLE_TIMESHIFT
|
||||
|
|
|
@ -177,6 +177,7 @@ void gtimer_disarm(gtimer_t *gti);
|
|||
/*
|
||||
* List / Queue header declarations
|
||||
*/
|
||||
LIST_HEAD(access_entry_list, access_entry);
|
||||
LIST_HEAD(th_subscription_list, th_subscription);
|
||||
LIST_HEAD(dvr_config_list, dvr_config);
|
||||
LIST_HEAD(dvr_entry_list, dvr_entry);
|
||||
|
|
|
@ -12,6 +12,10 @@ tvheadend.acleditor = function(panel)
|
|||
items: []
|
||||
});
|
||||
|
||||
var list = 'enabled,username,password,prefix,streaming,adv_streaming,' +
|
||||
'dvr,dvr_config,webui,admin,channel_min,channel_max,channel_tag,' +
|
||||
'comment';
|
||||
|
||||
tvheadend.idnode_grid(panel, {
|
||||
url: 'api/access/entry',
|
||||
comet: 'acl_entries',
|
||||
|
@ -20,10 +24,14 @@ tvheadend.acleditor = function(panel)
|
|||
tabIndex: 0,
|
||||
add: {
|
||||
url: 'api/access/entry',
|
||||
params: {
|
||||
list: list,
|
||||
},
|
||||
create: { }
|
||||
},
|
||||
del: true,
|
||||
move: true,
|
||||
list: list,
|
||||
help: function() {
|
||||
new tvheadend.help('Access Control Entries', 'config_access.html');
|
||||
},
|
||||
|
|
Loading…
Add table
Reference in a new issue